Railway Operation Simulator  v2.20.3
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 #include <windows.h>
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
251  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 
1108 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1109 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1110  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1111  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1112  {
1113  Utilities->CallLogPop(2566);
1114  return(1);
1115  }
1116  if(GetRouteGraphicPtr(0,1) == EXG)
1117  {
1118  Utilities->CallLogPop(2567);
1119  return(2);
1120  }
1121  if(GetRouteGraphicPtr(1,0) == EXG)
1122  {
1123  Utilities->CallLogPop(2568);
1124  return(3);
1125  }
1126  if(GetRouteGraphicPtr(1,1) == EXG)
1127  {
1128  Utilities->CallLogPop(2569);
1129  return(3);
1130  }
1131  Utilities->CallLogPop(2570);
1132  return(0);
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 // Track functions
1137 // ---------------------------------------------------------------------------
1138 
1139 // ---------------------------------------------------------------------------
1140 
1142 {
1143  TypeOfRoute = 0;
1144  ReducedTimePenalty = false;
1145  BarrierState = Up;
1146  ChangeDuration = 0.0;
1147  BaseElementSpeedTag = 1;
1148  HLoc = 0;
1149  VLoc = 0;
1150  StartTime = TDateTime(0);
1151 }
1152 
1153 // ---------------------------------------------------------------------------
1154 
1156 {
1157 // CurrentSpeedButtonTag = 0; //not assigned yet
1158 
1159  HLocMin = 2000000000;
1160  VLocMin = 2000000000;
1161  HLocMax = -2000000000;
1162  VLocMax = -2000000000;
1163  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1164  CopyFlag = false; // only true for copying, so names aren't copied
1165  AnsiString NL = '\n';
1166 
1167  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1168  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1169  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1170  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1171 
1176 
1177  int InternalLinkCheckArray[9][2] =
1178  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1179 
1180 /* array of valid link values for 'old' location and 'new' location, where
1181  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1182 
1183  for(int x = 0; x < 9; x++)
1184  {
1185  for(int y = 0; y < 2; y++)
1186  {
1187  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1188  }
1189  }
1190 
1191 // Platform and default track element values
1192  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1193 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1194  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1195  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1196  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1197  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1198  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1199  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1200  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1201  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1202  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1203  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1204 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1205 
1206  int HVArray[10][2] =
1207  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1208 
1209  for(int x = 0; x < 10; x++)
1210  {
1211  for(int y = 0; y < 2; y++)
1212  {
1213  LinkHVArray[x][y] = HVArray[x][y];
1214  }
1215  }
1216  TrackFinished = false;
1217 // DistancesSet = false;
1218 
1219  TSigElement TempSigTable[40] = // original four aspect
1220  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1221  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1222 
1223  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1224  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1225 
1228 
1229  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1230  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1231 
1232  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1233  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1234  {75, 4, RailGraphics->gl75}};
1235 
1236  for(int x = 0; x < 40; x++)
1237  {
1238  SigTable[x] = TempSigTable[x];
1239  }
1240 
1241  TSigElement TempSigTableThreeAspect[40] =
1242  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1243  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1244 
1245  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1246  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1247 
1248  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1249  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1250 
1251  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1252  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1253 
1254  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1255  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1256  {75, 4, RailGraphics->gl75}};
1257 
1258  for(int x = 0; x < 40; x++)
1259  {
1260  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1261  }
1262 
1263  TSigElement TempSigTableTwoAspect[40] =
1264  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1265  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1266 
1267  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1268  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1269 
1270  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1271  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1272 
1273  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1274  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1275 
1276  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1277  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1278  {75, 4, RailGraphics->gl75}};
1279 
1280  for(int x = 0; x < 40; x++)
1281  {
1282  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1283  }
1284 
1285  TSigElement TempSigTableGroundSignal[40] =
1289 
1293 
1297 
1301 
1302  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1305 
1306  for(int x = 0; x < 40; x++)
1307  {
1308  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1309  }
1310 
1311  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1312  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1313  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1314 
1315  for(int x = 0; x < 8; x++)
1316  {
1317  FailedSigTable[x] = TempFailedSigTable[x];
1318  }
1319 
1320  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1321  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1322  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1323 
1324  for(int x = 0; x < 8; x++)
1325  {
1326  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1327  }
1328 
1329 /*
1330  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1331  a single location. These are as follows:-
1332  Directly Adjacent = up, down, left or right - NOT diagonal.
1333  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1334  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1335  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1336 
1337  //t 76
1338  //b 77
1339  //l 78
1340  //r 79
1341  //c 96
1342  //v fb 129
1343  //h fb 130
1344  //v underpass 145
1345  //h underpass 146
1346  //n 131
1347 */
1348 
1349  int Tag76[25][3] =
1350  {{-1, 0, 96}, // c top plat
1351  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1352  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1353  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1354  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1355  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1356  {0, 0, 129}, {0, -1, 145}, // v up
1357  {0, 0, 145}};
1358 
1359  for(int x = 0; x < 25; x++)
1360  {
1361  for(int y = 0; y < 3; y++)
1362  {
1363  Tag76Array[x][y] = Tag76[x][y];
1364  }
1365  }
1366 
1367  int Tag77[25][3] =
1368  {{-1, 0, 96}, // c bot plat
1369  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1370  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1371  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1372  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1373  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1374  {0, 0, 129}, {0, 1, 145}, // v up
1375  {0, 0, 145}};
1376 
1377  for(int x = 0; x < 25; x++)
1378  {
1379  for(int y = 0; y < 3; y++)
1380  {
1381  Tag77Array[x][y] = Tag77[x][y];
1382  }
1383  }
1384 
1385  int Tag78[25][3] =
1386  {{-1, 0, 96}, // c left plat
1387  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1388  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1389  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1390  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1391  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1392  {0, 0, 130}, {-1, 0, 146}, // h up
1393  {0, 0, 146}};
1394 
1395  for(int x = 0; x < 25; x++)
1396  {
1397  for(int y = 0; y < 3; y++)
1398  {
1399  Tag78Array[x][y] = Tag78[x][y];
1400  }
1401  }
1402 
1403  int Tag79[25][3] =
1404  {{-1, 0, 96}, // c right plat
1405  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1406  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1407  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1408  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1409  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1410  {0, 0, 130}, {1, 0, 146}, // h up
1411  {0, 0, 146}};
1412 
1413  for(int x = 0; x < 25; x++)
1414  {
1415  for(int y = 0; y < 3; y++)
1416  {
1417  Tag79Array[x][y] = Tag79[x][y];
1418  }
1419  }
1420 
1421  int Tag96[28][3] =
1422  {{-1, 0, 96}, // c //concourse
1423  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1424  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1425  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1426  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1427  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1428  {0, -1, 129}, {1, 0, 130}, // h fb
1429  {-1, 0, 130}, {0, 1, 145}, // v up
1430  {0, -1, 145}, {1, 0, 146}, // h up
1431  {-1, 0, 146}};
1432 
1433  for(int x = 0; x < 28; x++)
1434  {
1435  for(int y = 0; y < 3; y++)
1436  {
1437  Tag96Array[x][y] = Tag96[x][y];
1438  }
1439  }
1440 
1441  int Tag129[8][3] = // vert fb
1442  {{0, -1, 96}, // c
1443  {0, -1, 77}, // b
1444  {0, -1, 129}, // v fb
1445 
1446  {0, 1, 96}, // c
1447  {0, 1, 76}, // t
1448  {0, 1, 129}, // v fb
1449 
1450  {0, 0, 76}, // t
1451  {0, 0, 77}}; // b
1452 
1453  for(int x = 0; x < 8; x++)
1454  {
1455  for(int y = 0; y < 3; y++)
1456  {
1457  Tag129Array[x][y] = Tag129[x][y];
1458  }
1459  }
1460 
1461  int Tag145[8][3] = // vert up
1462  {{0, -1, 96}, // c
1463  {0, -1, 77}, // b
1464  {0, -1, 145}, // v fb
1465 
1466  {0, 1, 96}, // c
1467  {0, 1, 76}, // t
1468  {0, 1, 145}, // v fb
1469 
1470  {0, 0, 76}, // t
1471  {0, 0, 77}}; // b
1472 
1473  for(int x = 0; x < 8; x++)
1474  {
1475  for(int y = 0; y < 3; y++)
1476  {
1477  Tag145Array[x][y] = Tag145[x][y];
1478  }
1479  }
1480 
1481  int Tag130[8][3] = // hor fb
1482  {{-1, 0, 96}, // c
1483  {-1, 0, 79}, // r
1484  {-1, 0, 130}, // h fb
1485 
1486  {1, 0, 96}, // c
1487  {1, 0, 78}, // l
1488  {1, 0, 130}, // h fb
1489 
1490  {0, 0, 78}, // l
1491  {0, 0, 79}}; // r
1492 
1493  for(int x = 0; x < 8; x++)
1494  {
1495  for(int y = 0; y < 3; y++)
1496  {
1497  Tag130Array[x][y] = Tag130[x][y];
1498  }
1499  }
1500 
1501  int Tag146[8][3] = // hor up
1502  {{-1, 0, 96}, // c
1503  {-1, 0, 79}, // r
1504  {-1, 0, 146}, // h fb
1505 
1506  {1, 0, 96}, // c
1507  {1, 0, 78}, // l
1508  {1, 0, 146}, // h fb
1509 
1510  {0, 0, 78}, // l
1511  {0, 0, 79}}; // r
1512 
1513  for(int x = 0; x < 8; x++)
1514  {
1515  for(int y = 0; y < 3; y++)
1516  {
1517  Tag146Array[x][y] = Tag146[x][y];
1518  }
1519  }
1520 
1521  int Tag131[4][3] =
1522  {{-1, 0, 131}, // n
1523  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1524 
1525  for(int x = 0; x < 4; x++)
1526  {
1527  for(int y = 0; y < 3; y++)
1528  {
1529  Tag131Array[x][y] = Tag131[x][y];
1530  }
1531  }
1532 
1533  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1534  {
1535  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1536  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1537  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1538  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1539  140, 144, 145, 146
1540  };
1541 
1542  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1543  {
1544  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1545  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1546  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1547  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1548  141, 144, 145, 146
1549  };
1550 
1551  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1552  {
1553  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1554  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1555  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1556  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1557  141, 144, 146, 145
1558  };
1559 
1560  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1561  {
1562  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1563  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1564  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1565  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1566  140, 144, 146, 145
1567  };
1568 
1569  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1570  {
1571  FlipArray[x] = InternalFlipArray[x];
1572  MirrorArray[x] = InternalMirrorArray[x];
1573  RotRightArray[x] = InternalRotRightArray[x];
1574  RotLeftArray[x] = InternalRotLeftArray[x];
1575  }
1576 }
1577 
1578 // ---------------------------------------------------------------------------
1580 {
1581 // delete TrackVectorPtr;
1582 // delete FixedTrackArrayPtr;
1583  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1584 
1585  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1586  {
1587  delete UGMIt->second;
1588  UGMIt++;
1589  }
1590  delete GapFlashGreen;
1591  delete GapFlashRed;
1592  // all the rest are cleared by the relevant automatic destructors
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1600  {
1601 // loc 0 not used, set to bmSolidBgnd
1605 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1625  };
1626 
1627  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1628  {
1629 // loc 0 not used, set to smSolidBgnd
1633 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1652  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1653  };
1654 
1655 // track types
1656  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1657  {
1658  Erase, // 1 0
1659  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1660  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1661  Crossover, Crossover, // 2 15-16
1662  Unused, // 17 (was for text in earlier development) //1 17
1665  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1669  Platform, Platform, Platform, Platform, // 4 76-79
1672  Concourse, // 1 96
1675  Simple, Simple, Simple, Simple, // 4 125-128
1676  FootCrossing, FootCrossing, // 2 129-130
1677  NamedNonStationLocation, // 1 131
1678  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1679  Simple, Simple, Simple, Simple, // 4 140-143
1680  LevelCrossing, // 1 144
1681  FootCrossing, FootCrossing // 2 145 & 146
1682  };
1683 
1684 // links
1685  int Links[FirstUnusedSpeedTagNumber][4] =
1686  {{-1, -1, -1, -1}, // erase element
1687  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1688  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1689 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1690  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1691  {-1, -1, -1, -1}, // unused
1692  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1693  {2, 7, -1, -1}, // simple
1694  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1695 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1696 // (or right diverging if no straight)
1697  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1698  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1699  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1700  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1701  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1702  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1704  {-1, -1, -1, -1}, // Concourse
1705  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1709  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1710  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1711  {-1, -1, -1, -1}, // NamedNonStationLocation
1712  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1713 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1714  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1715  {-1, -1, -1, -1}, // level crossing
1716  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1717  };
1718 
1720  {{NotSet, NotSet, NotSet, NotSet}, // unused
1724  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1726  {NotSet, NotSet, NotSet, NotSet}, // unused
1730  {Connection, Connection, NotSet, NotSet}, // simple
1734  {Lead, Trail, Lead, Trail}, // points
1736  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1744  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1750  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1759  {Connection, Connection, NotSet, NotSet}, // Arrows
1761  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1763  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1765  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1766  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1767  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1768  };
1769 
1770  for(int x = 0; x < 17; x++)
1771  {
1772  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1773  }
1774  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1775 // 17 was the old text value so don't want any graphics (now disused)
1776  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1777  {
1778  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1779  }
1780 }
1781 
1782 // ---------------------------------------------------------------------------
1783 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1784  ExistingGraphicLoaded(false), Width(16), Height(16)
1785 {
1786  OriginalGraphic = new Graphics::TBitmap;
1787  OriginalGraphic->PixelFormat = pf8bit;
1788  OriginalGraphic->Width = Width;
1789  OriginalGraphic->Height = Height;
1790  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1796  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1797 {
1798  OriginalGraphic = new Graphics::TBitmap;
1799  OriginalGraphic->PixelFormat = pf8bit;
1800  OriginalGraphic->Width = Width;
1801  OriginalGraphic->Height = Height;
1802  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1803 }
1804 
1805 // ---------------------------------------------------------------------------
1806 
1808 {
1809  delete OriginalGraphic;
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1815 {
1816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1817  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1818  VPos = VPosIn;
1819  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1820 
1821  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1822  SourceRect.init(Left, Top, Left + Width, Top + Height);
1823  ScreenSourceSet = true;
1824  Utilities->CallLogPop(422);
1825 }
1826 
1827 // ---------------------------------------------------------------------------
1828 
1830 {
1831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1832  if(!OverlayLoaded)
1833  {
1834  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1835  }
1836  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1837  {
1838  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1839  }
1840  if(!ScreenSourceSet)
1841  {
1842  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1843  }
1844  if(ExistingGraphicLoaded) // can only call one of the load functions
1845  {
1846  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1847  }
1848  if(OverlayPlotted) // don't load from screen if overlay plotted
1849  {
1850  Utilities->CallLogPop(775);
1851  return;
1852  }
1853  TRect DestRect(0, 0, Width, Height);
1854 
1856  OriginalLoaded = true;
1857  ScreenGraphicLoaded = true;
1858  Utilities->CallLogPop(423);
1859 }
1860 
1861 // ---------------------------------------------------------------------------
1862 
1863 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1864 /*
1865  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1866 */
1867 {
1868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1869  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1870  if(!OverlayLoaded)
1871  {
1872  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1873  }
1874  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1875  {
1876  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1877  }
1878  if(ScreenGraphicLoaded) // can only call one of the load functions
1879  {
1880  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1881  }
1882  Width = WidthIn;
1883  Height = HeightIn;
1884  OriginalGraphic->Width = Width;
1885  OriginalGraphic->Height = Height;
1886  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1887  VPos += VOffset;
1888  TRect DestRect(0, 0, Width, Height);
1889 
1890  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1891  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1892  OriginalLoaded = true;
1893  ExistingGraphicLoaded = true;
1894  Utilities->CallLogPop(424);
1895 }
1896 
1897 // ---------------------------------------------------------------------------
1898 
1899 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1900 {
1901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1902  OverlayGraphic = Overlay;
1903  OverlayLoaded = true;
1904  Utilities->CallLogPop(425);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1912  if(!OverlayLoaded)
1913  {
1914  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1915  }
1916  if(!OverlayPlotted)
1917  {
1918  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1919  Disp->Update();
1920  OverlayPlotted = true;
1921  }
1922  Utilities->CallLogPop(426);
1923 }
1924 
1925 // ---------------------------------------------------------------------------
1926 
1928 {
1929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1930  if(OverlayPlotted)
1931  {
1932  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1933  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1934  {
1935  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1936  }
1937  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1938  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1939  OverlayPlotted = false;
1940  }
1941  Utilities->CallLogPop(427);
1942 }
1943 
1944 // ---------------------------------------------------------------------------
1945 
1947 {
1948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1949  bool TrackPresent = false;
1950 
1951  if(InactiveTrackVector.size() != 0)
1952  {
1953  Utilities->CallLogPop(1333);
1954  return(false);
1955  }
1956  else if(TrackVector.size() == 0)
1957  {
1958  Utilities->CallLogPop(1334);
1959  return(true);
1960  }
1961  else
1962  {
1963  for(unsigned int x = 0; x < TrackVector.size(); x++)
1964  {
1965  if((TrackElementAt(1042, x).SpeedTag != 0))
1966  {
1967  TrackPresent = true;
1968  }
1969  }
1970  }
1971  Utilities->CallLogPop(1335);
1972  return(!TrackPresent);
1973 }
1974 
1975 // ---------------------------------------------------------------------------
1976 
1977 bool TTrack::NoActiveTrack(int Caller)
1978 {
1979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1980  bool TrackPresent = false;
1981 
1982  if(TrackVector.size() == 0)
1983  {
1984  Utilities->CallLogPop(1582);
1985  return(true);
1986  }
1987  else
1988  {
1989  for(unsigned int x = 0; x < TrackVector.size(); x++)
1990  {
1991  if((TrackElementAt(1043, x).SpeedTag != 0))
1992  {
1993  TrackPresent = true;
1994  }
1995  break;
1996  }
1997  }
1998  Utilities->CallLogPop(1583);
1999  return(!TrackPresent);
2000 }
2001 
2002 // ---------------------------------------------------------------------------
2003 
2004 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2005 {
2006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2007  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2008  TrackEraseSuccessfulFlag = false;
2009 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2010 // since have to match platforms as well as track
2011 // used to set TrackFinished to false if an element erased
2012 
2013  ErasedTrackVectorPosition = -1; // marker for no element erased
2014  AnsiString SName = "", ErrorString;
2016  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2017  TTrackMapIterator TrackMapPtr;
2018  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2019 
2020  if(TrackVector.size() != 0)
2021  {
2022  TrackMapKeyPair.first = HLocInput;
2023  TrackMapKeyPair.second = VLocInput;
2024  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2025  if(TrackMapPtr != TrackMap.end())
2026  {
2027  bool FoundFlag;
2028  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2029  if(FoundFlag) // should find it as it's in the map
2030  {
2031  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2032  {
2033  SName = TrackElementAt(1, VecPos).LocationName;
2034  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2035  if(ErrorString != "")
2036  {
2037  throw Exception(ErrorString + " for EraseTrackElement 1");
2038  }
2039  LocationNameMultiMap.erase(SNIt);
2040  }
2041  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2042  // ensure erase vector element before map element as iterator no longer valid after a map erase
2043  TrackMap.erase(TrackMapPtr);
2044  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2045  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2047  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2048  if(SName != "")
2049  {
2050  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2051  int HPos, VPos;
2052  if(TextHandler->FindText(1, SName, HPos, VPos))
2053  {
2054  if(TextHandler->TextErase(5, HPos, VPos, SName))
2055  {
2056  ;
2057  } // condition not used
2058 
2059  }
2060  }
2061  ErasedTrackVectorPosition = VecPos;
2062  TrackEraseSuccessfulFlag = true;
2063  }
2064  }
2065  }
2066  if(InactiveTrackVector.size() != 0)
2067  {
2068  unsigned int VecPos;
2069  InactiveTrackMapKeyPair.first = HLocInput;
2070  InactiveTrackMapKeyPair.second = VLocInput;
2071  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2072  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2073  {
2074  SName = "";
2075  VecPos = InactiveTrack2MultiMapIterator->second;
2076  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2077  {
2078  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2079  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2080  if(ErrorString != "")
2081  {
2082  throw Exception(ErrorString + " for EraseTrackElement 2A");
2083  }
2084  LocationNameMultiMap.erase(SNIt);
2085  }
2086  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2087  // ensure erase vector element before map element as iterator no longer valid after a map erase
2088  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2089  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2090  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2092  TrackEraseSuccessfulFlag = true;
2093  if(SName != "")
2094  {
2095  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2096  int HPos, VPos;
2097  if(TextHandler->FindText(2, SName, HPos, VPos))
2098  {
2099  if(TextHandler->TextErase(6, HPos, VPos, SName))
2100  {
2101  ;
2102  } // condition not used
2103 
2104  }
2105  }
2106  }
2107  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2108  {
2109  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2110  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2111  {
2112  SName = "";
2113  VecPos = InactiveTrack2MultiMapIterator->second;
2114  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2115  {
2116  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2117  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2118  if(ErrorString != "")
2119  {
2120  throw Exception(ErrorString + " for EraseTrackElement 2B");
2121  }
2122  LocationNameMultiMap.erase(SNIt);
2123  }
2124  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2125  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2126  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2128  if(SName != "")
2129  {
2130  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2131  int HPos, VPos;
2132  if(TextHandler->FindText(3, SName, HPos, VPos))
2133  {
2134  if(TextHandler->TextErase(7, HPos, VPos, SName))
2135  {
2136  ;
2137  } // condition not used
2138 
2139  }
2140  }
2141  }
2142  }
2143  }
2144  if(TrackEraseSuccessfulFlag)
2145  {
2146  CalcHLocMinEtc(2);
2147  SetTrackFinished(false);
2148  }
2149  if(InternalChecks)
2150  {
2151  CheckMapAndTrack(1); // test
2152  CheckMapAndInactiveTrack(1); // test
2153  CheckLocationNameMultiMap(6); // test
2154  }
2155  Utilities->CallLogPop(428);
2156 }
2157 
2158 // ---------------------------------------------------------------------------
2159 
2160 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks, bool PerformNameSearch)
2161 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2162 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2163 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2164 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2165 {
2166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2167  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2168  bool PlatAllowedFlag = false;
2169 
2170  TrackLinkingRequiredFlag = false;
2171 /*
2172  Not erase, that covered separately.
2173  First check if Current SpeedButton assigned, then check if a platform and only
2174  permit if an appropriate trackpiece already there & not a same platform there.
2175  - can't enter a platform without track first.
2176  Then for non-platforms, check if a track piece already present at location &
2177  reject if so.
2178 */
2179 
2180  TLocationNameMultiMapEntry LocationNameEntry;
2181 
2182  LocationNameEntry.first = "";
2183  if(CurrentTag == 0)
2184  {
2185  Utilities->CallLogPop(429);
2186  return; // not assigned yet
2187  }
2188  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2189 
2190  TempTrackElement.HLoc = HLocInput;
2191  TempTrackElement.VLoc = VLocInput;
2192  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2193 // new at version 0.6 - set signal aspect depending on build mode
2194 
2195  if(TempTrackElement.TrackType == SignalPost)
2196  {
2197  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2198  // pasting a SignalPost can only have values 1 to 4
2199  {
2201  {
2202  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2203  }
2205  {
2206  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2207  }
2209  {
2210  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2211  }
2212  else
2213  {
2214  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2215  }
2216  }
2217  else if(Aspect == 1)
2218  {
2219  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2220  }
2221  else if(Aspect == 2)
2222  {
2223  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2224  }
2225  else if(Aspect == 3)
2226  {
2227  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2228  }
2229  else
2230  {
2231  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2232  }
2233  }
2234  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2235  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2236  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2237  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2238 
2239  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2240  {
2242  {
2243  NonStationOrLevelCrossingPresent = true;
2244  }
2245  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2246  {
2247  NonStationOrLevelCrossingPresent = true;
2248  }
2249  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2250  {
2251  PlatformPresent = true;
2252  }
2253  // no need to check IMPair.second since if that exists it is because .first is a platform
2254  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2255  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2256  }
2257 // check platforms
2258  if(TempTrackElement.TrackType == Platform)
2259  {
2260  if(FoundFlag) // active track element already there
2261  {
2262  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2263  {
2264  ;
2265  }
2266  // same platform type already there so above keeps PlatAllowedFlag false
2267  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2268  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2269  {
2270  PlatAllowedFlag = true;
2271  }
2272  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2273  {
2274  PlatAllowedFlag = true;
2275  }
2276  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2277  {
2278  PlatAllowedFlag = true;
2279  }
2280  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2281  {
2282  PlatAllowedFlag = true;
2283  }
2284  if(PlatAllowedFlag)
2285  {
2286  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2287  TrackPush(1, TempTrackElement);
2288  if(PerformNameSearch)
2289  {
2290  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2291  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2292  // Must be called AFTER TrackPush
2293  // No need to plot the element - Clearand ... called after this function called
2294  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2295  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2296  }
2297 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2298 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2299 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2300  if(InternalChecks)
2301  {
2302  CheckMapAndInactiveTrack(5); // test
2303  CheckLocationNameMultiMap(4); // test
2304  }
2305  Utilities->CallLogPop(430);
2306  return;
2307  }
2308  } // if(FoundFlag)
2309 
2310  Utilities->CallLogPop(431);
2311  return;
2312  } // if platform
2313 
2314 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2315  if(TempTrackElement.TrackType == NamedNonStationLocation)
2316  {
2317  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2318  (!FoundFlag && !InactiveFoundFlag))
2319  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2320  {
2321  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2322  TrackPush(2, TempTrackElement);
2323  if(PerformNameSearch)
2324  {
2325  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2329  {
2330 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2331 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2332 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2333  }
2334  if(InternalChecks)
2335  {
2336  CheckMapAndInactiveTrack(11); // test
2337  CheckLocationNameMultiMap(12); // test
2338  }
2339  Utilities->CallLogPop(432);
2340  return;
2341  }
2342  else
2343  {
2344  Utilities->CallLogPop(433);
2345  return;
2346  }
2347  }
2348 // check if a level crossing - OK if placed on a plain straight track
2349  if(TempTrackElement.TrackType == LevelCrossing)
2350  {
2351  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2352  {
2353  TrackPush(11, TempTrackElement);
2354  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2355 // no need for reference to LC element as can't be open
2356  TrackLinkingRequiredFlag = true;
2357  Utilities->CallLogPop(1907);
2358  return;
2359  }
2360  else
2361  {
2362  Utilities->CallLogPop(1906);
2363  return; // was a level crossing but can't place it for some reason
2364  }
2365  }
2366 
2367 // check if another element already there
2368  else if(FoundFlag || InactiveFoundFlag)
2369  {
2370  Utilities->CallLogPop(434);
2371  return; // something already there (active or inactive track)
2372  }
2373 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2374 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2375 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2376 // do this after pushed into vector so that can use EnterLocationName
2377 
2378  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2379  {
2380  TrackPush(3, TempTrackElement);
2381  if(PerformNameSearch)
2382  {
2383  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2384  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2385  }
2386  }
2387  else if(TempTrackElement.TrackType == Points)
2388  {
2389  TrackPush(4, TempTrackElement);
2390  bool BothPointFillets = true;
2391  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2392  }
2393  else if(TempTrackElement.TrackType == SignalPost)
2394  {
2395  TrackPush(10, TempTrackElement);
2396  PlotSignal(12, TempTrackElement, Display);
2397  }
2398  else
2399  {
2400  TrackPush(5, TempTrackElement);
2401  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2402  }
2403  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2404  {
2405  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2406  }
2407  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2408  {
2409  CheckMapAndTrack(2); // test
2410  CheckMapAndInactiveTrack(2); // test
2411  CheckLocationNameMultiMap(5); // test
2412  }
2413  Utilities->CallLogPop(2062);
2414 }
2415 
2416 // ---------------------------------------------------------------------------
2417 
2418 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2419  bool InternalChecks)
2420 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2421 {
2422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2423  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2424  bool PlatAllowedFlag = false;
2425 
2426  TrackLinkingRequiredFlag = false;
2427  TLocationNameMultiMapEntry LocationNameEntry;
2428 
2429  LocationNameEntry.first = "";
2430  if(TempTrackElement.SpeedTag == 0)
2431  {
2432  Utilities->CallLogPop(2063);
2433  return; // not assigned yet
2434  }
2435  TempTrackElement.HLoc = HLocInput;
2436  TempTrackElement.VLoc = VLocInput;
2437  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2438  for(int x = 0; x < 4; x++) // unset any gaps,
2439  {
2440  if(TempTrackElement.Config[x] == Gap)
2441  {
2442  TempTrackElement.ConnLinkPos[x] = -1;
2443  }
2444  TempTrackElement.Conn[x] = -1;
2445  }
2446  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2447 // new at version 0.6 - set signal aspect depending on build mode
2448  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2449 
2450  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2451  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2452  // for the active track element because these aren't set
2453  // if don't do this then get a mismatch error during map checks later
2454 
2455  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2456 
2457  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2458  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2459 
2460  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2461  {
2462  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2463  {
2464  NonStationOrLevelCrossingPresent = true;
2465  }
2466  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2467  {
2468  NonStationOrLevelCrossingPresent = true;
2469  }
2470  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2471  {
2472  PlatformPresent = true;
2473  }
2474  // no need to check IMPair.second since if that exists it is because .first is a platform
2475  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2476  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2477  }
2478 // check platforms
2479  if(TempTrackElement.TrackType == Platform)
2480  {
2481  if(FoundFlag) // active track element already there
2482  {
2483  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2484  {
2485  ;
2486  }
2487  // same platform type already there so above keeps PlatAllowedFlag false
2488  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2489  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2490  {
2491  PlatAllowedFlag = true;
2492  }
2493  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2494  {
2495  PlatAllowedFlag = true;
2496  }
2497  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2498  {
2499  PlatAllowedFlag = true;
2500  }
2501  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2502  {
2503  PlatAllowedFlag = true;
2504  }
2505  if(PlatAllowedFlag)
2506  {
2507  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2508  TrackPush(12, TempTrackElement);
2509 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2510  {
2511  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2512  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2513  }
2514  // Must be called AFTER TrackPush
2515 // No need to plot the element - Clearand ... called after this function called
2516  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2517  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2518 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2519 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2520 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2521  if(InternalChecks)
2522  {
2523  CheckMapAndInactiveTrack(12); // test
2524  CheckLocationNameMultiMap(20); // test
2525  }
2526  Utilities->CallLogPop(2064);
2527  return;
2528  }
2529  } // if(FoundFlag)
2530 
2531  Utilities->CallLogPop(2065);
2532  return;
2533  } // if platform
2534 
2535 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2536  if(TempTrackElement.TrackType == NamedNonStationLocation)
2537  {
2538  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2539  (!FoundFlag && !InactiveFoundFlag))
2540  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2541  {
2542  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2543  TrackPush(13, TempTrackElement);
2544 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2545  {
2546  {
2547  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2548  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2549  }
2550  }
2551  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2552  {
2553 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2554 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2555 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2556  }
2557  if(InternalChecks)
2558  {
2559  CheckMapAndInactiveTrack(13); // test
2560  CheckLocationNameMultiMap(21); // test
2561  }
2562  Utilities->CallLogPop(2066);
2563  return;
2564  }
2565  else
2566  {
2567  Utilities->CallLogPop(2067);
2568  return;
2569  }
2570  }
2571 // check if a level crossing - OK if placed on a plain straight track
2572  if(TempTrackElement.TrackType == LevelCrossing)
2573  {
2574  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2575  {
2576  TrackPush(14, TempTrackElement);
2577  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2578 // no need for reference to LC element as can't be open
2579  TrackLinkingRequiredFlag = true;
2580  Utilities->CallLogPop(2068);
2581  return;
2582  }
2583  else
2584  {
2585  Utilities->CallLogPop(2069);
2586  return; // was a level crossing but can't place it for some reason
2587  }
2588  }
2589 
2590 // check if another element already there
2591  else if(FoundFlag || InactiveFoundFlag)
2592  {
2593  Utilities->CallLogPop(2070);
2594  return; // something already there (active or inactive track)
2595  }
2596 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2597 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2598 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2599 // do this after pushed into vector so that can use EnterLocationName
2600 
2601  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2602  {
2603  TrackPush(15, TempTrackElement);
2604  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2605  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2606  }
2607  else if(TempTrackElement.TrackType == Points)
2608  {
2609  TrackPush(16, TempTrackElement);
2610  bool BothPointFillets = true;
2611  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2612  }
2613  else if(TempTrackElement.TrackType == SignalPost)
2614  {
2615  TrackPush(17, TempTrackElement);
2616  PlotSignal(14, TempTrackElement, Display);
2617  }
2618  else
2619  {
2620  TrackPush(18, TempTrackElement);
2621  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2622  }
2623  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2624  {
2625  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2626  }
2627  if(InternalChecks)
2628  {
2629  CheckMapAndTrack(12); // test
2630  CheckMapAndInactiveTrack(14); // test
2631  CheckLocationNameMultiMap(22); // test
2632  }
2633  Utilities->CallLogPop(2071);
2634 }
2635 
2636 // ---------------------------------------------------------------------------
2637 
2638 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2639 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2640 // return bool = true for success
2641 // LocError = true for location error & HLoc & VLoc to be inverted
2642 {
2643  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2644  LocError = false;
2645  SetTrackFinished(false);
2646  if(TrackVector.size() == 0)
2647  {
2648  Utilities->CallLogPop(437);
2649  return(false);
2650  }
2651  if(GapsUnset(7))
2652  {
2653  if(GiveMessages)
2654  {
2655  ShowMessage("Gaps must be set before track can be validated");
2656  }
2657  Utilities->CallLogPop(1135);
2658  return(false);
2659  }
2660 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2661 // returns true for any unset gaps
2663  {
2664  // can keep this exception as protected by the GapsUnset call above
2665  throw Exception("Error, gaps unset when TryToConnectTrack called");
2666  }
2668  CheckGapMap(1); // test
2669 // Gap connections now securely defined
2670 
2671  CheckMapAndTrack(8); // test
2672 
2673 // Perform a pre-check prior to TrackMap being compiled
2674  if(GiveMessages)
2675  {
2676  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2677  {
2678  Utilities->CallLogPop(439);
2679  return(false);
2680  }
2681  }
2682  else
2683  {
2684  if(!LinkTrackNoMessages(1, false))
2685  {
2686  Utilities->CallLogPop(1131);
2687  return(false);
2688  }
2689  }
2690 // here if pre-check successful
2691  if(!RepositionAndMapTrack(0))
2692  {
2693  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2694  Utilities->CallLogPop(1138);
2695  return(false);
2696  }
2697 // now perform the final assembly - FinalCall = true
2698  if(GiveMessages)
2699  {
2700  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2701  {
2702  Utilities->CallLogPop(1116);
2703  return(false);
2704  }
2705  }
2706  else
2707  {
2708  if(!LinkTrackNoMessages(2, true))
2709  {
2710  Utilities->CallLogPop(1132);
2711  return(false);
2712  }
2713  }
2714 // success
2715 
2716  PopulateLCVector(0);
2717  CheckGapMap(2); // test
2718  CheckMapAndTrack(3); // test
2719  CheckMapAndInactiveTrack(3); // test
2720  CheckLocationNameMultiMap(9); // test
2721  SetTrackFinished(true);
2722 
2723 // Build ContinuationNameMap
2724  std::pair<AnsiString, char>TempMapPair;
2725 
2726  ContinuationNameMap.clear();
2727  for(int x = 0; x < Track->TrackVectorSize(); x++)
2728  {
2729  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2730  {
2731  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2732  TempMapPair.second = 'x'; // unused
2733  ContinuationNameMap.insert(TempMapPair);
2734  }
2735  }
2736 
2737 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2738 //(don't report blue areas without track as these unlikely to be mistakes)
2739 
2740  if(TrackFinished)
2741  {
2742  AnsiString Name = "";
2743  typedef std::list<AnsiString> TNoPlatsList;
2744  TNoPlatsList::iterator NPLIt;
2745  TNoPlatsList NoPlatsList;
2746  typedef std::list<AnsiString> TLocNameList;
2747  TLocNameList LocNameList; //single entry for each name
2750  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2751  {
2752  LocNameList.push_back(LNMMIt->first);
2753  }
2754  LocNameList.sort();
2755  LocNameList.unique();
2756  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2757  {
2758  Name = *LNLIt;
2759  MMRange = LocationNameMultiMap.equal_range(Name);
2760  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2761  {
2762  continue;
2763  }
2764  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2765  {
2766  if((LNMMIt->second) < 0) //active track element
2767  {
2768  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2769  {
2770  break;
2771  }
2772  }
2773  else //inactive
2774  {
2775  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2776  {
2777  break;
2778  }
2779  }
2780  TempIt = MMRange.second;
2781  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2782  {
2783  NoPlatsList.push_back(Name);
2784  }
2785  }
2786  }
2787  if(!NoPlatsList.empty())
2788  {
2789  AnsiString NoPlatsAnsiList = "";
2790  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2791  {
2792  NoPlatsAnsiList += *NPLIt + '\n';
2793  }
2794  if(!NoPlatsMessageSent)
2795  {
2796  if(NoPlatsList.size() > 1)
2797  {
2798  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2799  }
2800  else
2801  {
2802  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2803  }
2804  NoPlatsMessageSent = true;
2805  }
2806  }
2807  }
2808  Utilities->CallLogPop(440);
2809  return(true);
2810 }
2811 
2812 // ---------------------------------------------------------------------------
2813 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2814 // unused - too time-consuming - double brute force search
2815 {
2816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2817  int NewHLoc, NewVLoc;
2818  bool ConnectionFoundFlag, LinkFoundFlag;
2819 
2820  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2821  {
2822  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2823  {
2824  if(TrackElementAt(1061, x).Link[y] <= 0)
2825  {
2826  continue; // no link
2827  }
2828  if(TrackElementAt(1062, x).Config[y] == End)
2829  {
2830  continue; // buffer or continuation
2831  }
2832  if(TrackElementAt(1063, x).Config[y] == Gap)
2833  {
2834  continue; // gap jump
2835  }
2836  // get required H & V for track element joining link 'y'
2837  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2838  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2839  // find track element if present
2840  ConnectionFoundFlag = false;
2841  for(unsigned int z = 0; z < TrackVector.size(); z++)
2842  {
2843 // if(TrackElementAt(5, z).TrackType == Platform)
2844 // continue; //skip platforms
2845  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2846  {
2847  ConnectionFoundFlag = true;
2848  // find connecting link in the newly found track element if there is one
2849  LinkFoundFlag = false;
2850  for(unsigned int a = 0; a < 4; a++)
2851  {
2852  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2853  {
2854  LinkFoundFlag = true;
2855  }
2856  }
2857  // if there isn't a corresponding link set the invert values for the offending element
2858  if(!LinkFoundFlag)
2859  {
2860  HLoc = TrackElementAt(1072, x).HLoc;
2861  VLoc = TrackElementAt(1073, x).VLoc;
2862  Utilities->CallLogPop(441);
2863  return(true);
2864  }
2865  break; // success, so break out of 'z' loop
2866  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2867 
2868  } // for z...
2869  // if there isn't a connection set the invert values for the offending element
2870  if(!ConnectionFoundFlag)
2871  {
2872  HLoc = TrackElementAt(1074, x).HLoc;
2873  VLoc = TrackElementAt(1075, x).VLoc;
2874  Utilities->CallLogPop(442);
2875  return(true);
2876  }
2877  } // for y....
2878  } // for x...
2879  Utilities->CallLogPop(443);
2880  return(false); // all OK
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2886 {
2887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2888  TrackElement.LogTrack(0));
2889  bool FoundFlag;
2890 
2891  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2892  if(FoundFlag)
2893  {
2894  TrackElement = TrackElementAt(1076, Position);
2895  }
2896  Utilities->CallLogPop(444);
2897  return(FoundFlag);
2898 }
2899 
2900 // ---------------------------------------------------------------------------
2901 
2903 {
2904  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2905  if(NextTrackElementPtr >= TrackVector.end())
2906  {
2907  Utilities->CallLogPop(1336);
2908  return(false);
2909  }
2910  Next = *NextTrackElementPtr;
2912  Utilities->CallLogPop(1337);
2913  return(true);
2914 }
2915 
2916 // ---------------------------------------------------------------------------
2917 
2919 {
2920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2922  {
2923  Utilities->CallLogPop(1338);
2924  return(false);
2925  }
2926  Next = *NextTrackElementPtr;
2928  Utilities->CallLogPop(1339);
2929  return(true);
2930 }
2931 
2932 // ---------------------------------------------------------------------------
2933 
2934 int TTrack::NumberOfGaps(int Caller)
2935 
2936 {
2937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2938  int Count = 0;
2939 
2940  if(TrackVector.size() == 0)
2941  {
2942  Utilities->CallLogPop(1340);
2943  return(0);
2944  }
2945  for(unsigned int x = 0; x < TrackVector.size(); x++)
2946  {
2947  if(TrackElementAt(1077, x).TrackType == GapJump)
2948  {
2949  Count++;
2950  }
2951  }
2952  Utilities->CallLogPop(1341);
2953  return(Count);
2954 }
2955 
2956 // ---------------------------------------------------------------------------
2958 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2959 // returns true for any unset gaps
2960 {
2961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2962  bool UnsetGaps = false;
2963 
2964  if(TrackVector.size() == 0)
2965  {
2966  Utilities->CallLogPop(445);
2967  return(false);
2968  }
2969  for(unsigned int x = 0; x < TrackVector.size(); x++)
2970  {
2971  if(TrackElementAt(1078, x).TrackType != GapJump)
2972  {
2973  for(unsigned int y = 0; y < 4; y++)
2974  {
2975  TrackElementAt(1079, x).Conn[y] = -1;
2976  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2977  }
2978  }
2979  else // GapJump
2980  {
2981 // int tempint = TrackElementAt(, x).Conn[0);
2982 
2983  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2984  {
2985  for(unsigned int y = 0; y < 4; y++)
2986  {
2987  TrackElementAt(1082, x).Conn[y] = -1;
2988  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2989  }
2990  UnsetGaps = true;
2991  continue; // to next 'x'
2992  }
2993  else // set, but may not have matching element, or that element may not be set
2994  {
2995  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2996  {
2997  TrackElementAt(1084, x).Conn[y] = -1;
2998  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2999  }
3000 
3001  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3002  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3003  {
3004  for(unsigned int y = 0; y < 4; y++)
3005  {
3006  TrackElementAt(1087, x).Conn[y] = -1;
3007  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3008  }
3009  UnsetGaps = true;
3010  continue; // to next 'x'
3011  }
3012 // here if gap connection is itself a GapJump
3013  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3014  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3015  // if not clear Conns & CLks & reset Lk[0]
3016  {
3017  for(unsigned int y = 0; y < 4; y++)
3018  {
3019  TrackElementAt(1090, x).Conn[y] = -1;
3020  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3021  }
3022  UnsetGaps = true;
3023  continue; // to next 'x'
3024  }
3025 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3026 // hence no more action needed on these Conns & CLks
3027  }
3028  } // else //gap jump
3029 
3030  } // for x...
3031  Utilities->CallLogPop(446);
3032  return(UnsetGaps);
3033 }
3034 
3035 // ---------------------------------------------------------------------------
3036 
3037 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3038 {
3039 // VecFile already open and its pointer at right place on calling
3040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3041  int TempInt;
3042 
3043  TrackClear(1);
3044 // load track elements
3045  int NumberOfActiveElements = 0;
3046 
3047  GraphicsFollow = false;
3048  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3049  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3050 
3051  if(MarkerString[MarkerString.Length()] == '1')
3052  {
3053  GraphicsFollow = true;
3054  }
3055  for(int x = 0; x < NumberOfActiveElements; x++)
3056  {
3057  VecFile >> TempInt; // TrackVectorNumber, not used
3058  VecFile >> TempInt; // SpeedTag
3059  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3060  VecFile >> TempInt;
3061  TrackElement.HLoc = TempInt;
3062  VecFile >> TempInt;
3063  TrackElement.VLoc = TempInt;
3064  if(TrackElement.TrackType == GapJump)
3065  {
3066  VecFile >> TempInt;
3067  TrackElement.ConnLinkPos[0] = TempInt;
3068  VecFile >> TempInt;
3069  TrackElement.Conn[0] = TempInt;
3070  }
3071  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3072  {
3073  VecFile >> TempInt;
3074  TrackElement.Attribute = TempInt;
3075  }
3076  if(TrackElement.TrackType == SignalPost)
3077  {
3078  VecFile >> TempInt;
3079  if(TempInt == 0)
3080  {
3081  TrackElement.CallingOnSet = false;
3082  }
3083  else
3084  {
3085  TrackElement.CallingOnSet = true;
3086  }
3087  }
3088  VecFile >> TempInt;
3089  TrackElement.Length01 = TempInt;
3090  VecFile >> TempInt;
3091  TrackElement.Length23 = TempInt;
3092  VecFile >> TempInt;
3093  if((TempInt != -1) && (TempInt < 10))
3094  {
3095  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3096  }
3097  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3098  {
3099  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3100  }
3101  TrackElement.SpeedLimit01 = TempInt;
3102  VecFile >> TempInt;
3103  if((TempInt != -1) && (TempInt < 10))
3104  {
3105  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3106  }
3107  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3108  {
3109  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3110  }
3111  TrackElement.SpeedLimit23 = TempInt;
3112 
3113  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3114  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3115  SetElementID(0, TrackElement);
3116  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3117 // new for v0.6
3118  if(TrackElement.TrackType == SignalPost)
3119  {
3120  if(Marker[1] == '3')
3121  {
3122  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3123  }
3124  else if(Marker[1] == '2')
3125  {
3126  TrackElement.SigAspect = TTrackElement::TwoAspect;
3127  }
3128  else if(Marker[1] == 'G')
3129  {
3130  TrackElement.SigAspect = TTrackElement::GroundSignal;
3131  }
3132  else
3133  {
3134  TrackElement.SigAspect = TTrackElement::FourAspect;
3135  }
3136  }
3137  if(TrackElement.SpeedTag != 0)
3138  {
3139  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3140  }
3141  }
3142  int NumberOfInactiveElements = 0;
3143 
3144  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3145  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3146  for(int x = 0; x < NumberOfInactiveElements; x++)
3147  {
3148  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3149  VecFile >> TempInt; // SpeedTag
3150  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3151  VecFile >> TempInt;
3152  TrackElement.HLoc = TempInt;
3153  VecFile >> TempInt;
3154  TrackElement.VLoc = TempInt;
3155  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3156  SetElementID(3, TrackElement);
3157  TrackPush(9, TrackElement);
3158  Utilities->LoadFileString(VecFile); // marker
3159  }
3160  bool LocError = false; // needed for TryToConnectTrack but not used
3161  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3162 
3163  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3164  {
3165  SetTrackFinished(true);
3166  }
3167  else
3168  {
3169  SetTrackFinished(false);
3170  }
3171 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3172 // CheckMapAndInactiveTrack(8);
3173 // CheckLocationNameMultiMap(10);
3174  Utilities->CallLogPop(448);
3175 }
3176 
3177 // ---------------------------------------------------------------------------
3178 
3179 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3180 {
3181 // VecFile already open and its pointer at right place on calling
3182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3183 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3184 // & load into UserGraphicItem then store in UserGraphicVector
3185  UserGraphicVector.clear();
3186  TUserGraphicItem UGI;
3187  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3188 
3189  for(int x = 0; x < NumberOfGraphics; x++)
3190  {
3191  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3192  UGI.HPos = Utilities->LoadFileInt(VecFile);
3193  UGI.VPos = Utilities->LoadFileInt(VecFile);
3194  UGI.Width = 0; // provisional value
3195  UGI.Height = 0; // provisional value
3196  UGI.UserGraphic = NULL; // provisional value
3197  UserGraphicVector.push_back(UGI);
3198  }
3199 // now load the map & set Width, Height & TPicture*
3200  bool FileError = false;
3201 
3202  for(int x = 0; x < NumberOfGraphics; x++)
3203  {
3204  if(FileError)
3205  {
3206  break; // otherwise keeps going round the loop
3207  }
3208  UGI = UserGraphicVectorAt(0, x);
3209  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3210  {
3211  try
3212  {
3213 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(1, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  else
3256  {
3257  bool FoundInMap = false;
3258  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3259  {
3260  if(UGI.FileName == UGMIt->first) // already exists in map
3261  {
3262  UGI.UserGraphic = UGMIt->second;
3263  UGI.Width = UGI.UserGraphic->Width;
3264  UGI.Height = UGI.UserGraphic->Height;
3265  UserGraphicVectorAt(2, x) = UGI;
3266  FoundInMap = true;
3267  break;
3268  }
3269  }
3270  if(!FoundInMap)
3271  {
3272  try
3273  {
3275  UGME.first = UGI.FileName;
3276  UGME.second = new TPicture;
3277  UGME.second->LoadFromFile(UGME.first); // errors caught below
3278  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3279  {
3280  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3281  }
3282  UGI.UserGraphic = UGME.second;
3283  UGI.Width = UGI.UserGraphic->Width;
3284  UGI.Height = UGI.UserGraphic->Height;
3285  UserGraphicVectorAt(3, x) = UGI;
3286  }
3287  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3288  {
3289  //message already sent in CheckUserGraphics
3290  FileError = true;
3291  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3292  if(!UserGraphicMap.empty())
3293  {
3294  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3295  {
3296  delete UGMIt->second;
3297  }
3298  UserGraphicMap.clear();
3299  }
3300  }
3301  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3302  {
3303  //message already sent in CheckUserGraphics
3304  FileError = true;
3305  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3306  if(!UserGraphicMap.empty())
3307  {
3308  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3309  {
3310  delete UGMIt->second;
3311  }
3312  UserGraphicMap.clear();
3313  }
3314  }
3315  }
3316  }
3317  }
3318  Utilities->CallLogPop(2167);
3319 }
3320 
3321 // ---------------------------------------------------------------------------
3322 
3323 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3324 {
3325 // VecFile already open and its pointer at right place on calling
3326 // if GraphicsFollow true, then save Marker as **Active elements**1
3327 // save trackfinished flag
3328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3329  TTrackElement TrackElement, InactiveTrackElement;
3330 
3331 // save track elements
3332  Utilities->SaveFileInt(VecFile, TrackVector.size());
3333  if(GraphicsFollow)
3334  {
3335  VecFile << "**Active elements**1" << '\0' << '\n';
3336  }
3337  else
3338  {
3339  VecFile << "**Active elements**" << '\0' << '\n';
3340  }
3341  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3342  {
3343  TrackElement = TrackElementAt(1092, x);
3344  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3345  VecFile << TrackElement.SpeedTag << '\n';
3346  VecFile << TrackElement.HLoc << '\n';
3347  VecFile << TrackElement.VLoc << '\n';
3348  if(TrackElement.TrackType == GapJump)
3349  {
3350  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3351  VecFile << TrackElement.Conn[0] << '\n';
3352  }
3353  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3354  {
3355  VecFile << TrackElement.Attribute << '\n';
3356  }
3357  if(TrackElement.TrackType == SignalPost)
3358  {
3359  if(TrackElement.CallingOnSet)
3360  {
3361  VecFile << int(1) << '\n';
3362  }
3363  else
3364  {
3365  VecFile << int(0) << '\n';
3366  }
3367  }
3368  VecFile << TrackElement.Length01 << '\n';
3369  VecFile << TrackElement.Length23 << '\n';
3370  VecFile << TrackElement.SpeedLimit01 << '\n';
3371  VecFile << TrackElement.SpeedLimit23 << '\n';
3372  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3373  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374 // new for v0.6
3375  if(TrackElement.TrackType == SignalPost)
3376  {
3377  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3378  {
3379  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3380  }
3381  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3382  {
3383  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3384  }
3385  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3386  {
3387  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3388  }
3389  else // 4 aspect
3390  {
3391  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3392  }
3393  }
3394  else
3395  {
3396  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3397  }
3398  }
3399 
3400  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3401  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3402  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3403  {
3404  InactiveTrackElement = InactiveTrackElementAt(136, x);
3405  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3406  VecFile << InactiveTrackElement.SpeedTag << '\n';
3407  VecFile << InactiveTrackElement.HLoc << '\n';
3408  VecFile << InactiveTrackElement.VLoc << '\n';
3409  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3410  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3411  }
3412  Utilities->CallLogPop(449);
3413 }
3414 
3415 // ---------------------------------------------------------------------------
3416 
3417 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3418 {
3419 // VecFile already open and its pointer at right place on calling
3420 // check trackfinished flag
3421 // inactive elements follow immediately after active elements, no need to check for a marker between them
3422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3423  int TempInt;
3424 
3425  GraphicsFollow = false;
3426  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3427  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3428  {
3429  Utilities->CallLogPop(1513);
3430  return(false);
3431  }
3432 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3433  AnsiString MarkerString;
3434 
3435  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3436  {
3437  Utilities->CallLogPop(1758);
3438  return(false);
3439  }
3440  if(MarkerString[MarkerString.Length()] == '1')
3441  {
3442  GraphicsFollow = true;
3443  }
3444  for(int x = 0; x < NumberOfActiveElements; x++)
3445  {
3446  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3447  {
3448  Utilities->CallLogPop(1759);
3449  return(false);
3450  }
3451  VecFile >> TempInt;
3452  int SpeedTag = TempInt;
3453  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3454  {
3455  Utilities->CallLogPop(1514);
3456  return(false);
3457  }
3458  VecFile >> TempInt;
3459  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3460  {
3461  Utilities->CallLogPop(1495);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3466  {
3467  Utilities->CallLogPop(1497);
3468  return(false);
3469  }
3470  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3471  {
3472  VecFile >> TempInt;
3473  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3474  {
3475  Utilities->CallLogPop(1499);
3476  return(false);
3477  }
3478  VecFile >> TempInt;
3479  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3480  {
3481  Utilities->CallLogPop(1500);
3482  return(false);
3483  }
3484  }
3485  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3486  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3487  {
3488  VecFile >> TempInt;
3489  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3490  {
3491  Utilities->CallLogPop(1502);
3492  return(false);
3493  }
3494  }
3495  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3496  {
3497  VecFile >> TempInt;
3498  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3499  {
3500  Utilities->CallLogPop(1155);
3501  return(false);
3502  }
3503  }
3504  VecFile >> TempInt;
3505  if((TempInt < -1) || (TempInt > 999999)) // Length01
3506  {
3507  Utilities->CallLogPop(1503);
3508  return(false);
3509  }
3510  VecFile >> TempInt;
3511  if((TempInt < -1) || (TempInt > 999999)) // Length23
3512  {
3513  Utilities->CallLogPop(1504);
3514  return(false);
3515  }
3516  VecFile >> TempInt;
3517  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3518  {
3519  Utilities->CallLogPop(1505);
3520  return(false);
3521  }
3522  VecFile >> TempInt;
3523  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3524  {
3525  Utilities->CallLogPop(1506);
3526  return(false);
3527  }
3528  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3529  {
3530  Utilities->CallLogPop(1142);
3531  return(false); // LocationName
3532  }
3533  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3534  {
3535  Utilities->CallLogPop(1143);
3536  return(false); // ActiveTrackElementName
3537  }
3538  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3539  {
3540  Utilities->CallLogPop(1787);
3541  return(false); // marker
3542  }
3543  }
3544  int NumberOfInactiveElements = 0;
3545 
3546  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3547  if(NumberOfInactiveElements < 0) // No of active elements
3548  {
3549  Utilities->CallLogPop(1493);
3550  return(false);
3551  }
3552  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3553  {
3554  Utilities->CallLogPop(1764);
3555  return(false); // **Inactive elements** marker
3556  }
3557  for(int x = 0; x < NumberOfInactiveElements; x++)
3558  {
3559  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3560  {
3561  Utilities->CallLogPop(1765);
3562  return(false);
3563  }
3564  VecFile >> TempInt;
3565  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3566  {
3567  Utilities->CallLogPop(1494);
3568  return(false);
3569  }
3570  VecFile >> TempInt;
3571  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3572  {
3573  Utilities->CallLogPop(1496);
3574  return(false);
3575  }
3576  VecFile >> TempInt;
3577  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3578  {
3579  Utilities->CallLogPop(1498);
3580  return(false);
3581  }
3582  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3583  {
3584  Utilities->CallLogPop(1144);
3585  return(false); // LocationName
3586  }
3587  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3588  {
3589  Utilities->CallLogPop(1788);
3590  return(false); // marker
3591  }
3592  }
3593  Utilities->CallLogPop(1507);
3594  return(true);
3595 }
3596 
3597 // ---------------------------------------------------------------------------
3598 
3599 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3600 {
3601  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3602  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3603 
3604  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3605  {
3606  Utilities->CallLogPop(2168);
3607  return(false);
3608  }
3609  // filename in Graphics folder, then HPos, then VPos
3610  AnsiString FileName = "", TempStr = "";
3611 
3612  for(int x = 0; x < NumberOfGraphics; x++)
3613  {
3614  TPicture *TempPicture = new TPicture;
3615  try
3616  {
3617  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3618  {
3619  Utilities->CallLogPop(2169);
3620  delete TempPicture;
3621  return(false);
3622  }
3623  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3624  delete TempPicture;
3625  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3626  {
3627  Utilities->CallLogPop(2170);
3628  return(false);
3629  }
3630  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3631  {
3632  Utilities->CallLogPop(2171);
3633  return(false);
3634  }
3635  }
3636  catch(const EInvalidGraphic &e) //non error catch
3637  {
3638  //move file pointer to end of graphic section for later checks in session files
3639  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3640  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3641  for(int y = x + 1; y < NumberOfGraphics; y++)
3642  {
3643  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3644  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3645  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3646  }
3647  ShowMessage(FileName +
3648  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3649  Utilities->CallLogPop(2172);
3650  delete TempPicture;
3651  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3652  }
3653  catch(const Exception &e) //non error catch
3654  {
3655  //move file pointer to end of graphic section for later checks in session files
3656  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3657  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3658  for(int y = x + 1; y < NumberOfGraphics; y++)
3659  {
3660  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3661  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3662  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3663  }
3664  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3665  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3666  Utilities->CallLogPop(2173);
3667  delete TempPicture;
3668  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3669  }
3670  }
3671  Utilities->CallLogPop(2174);
3672  return(true);
3673 }
3674 
3675 // ---------------------------------------------------------------------------
3676 
3677 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3678 {
3679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3680  int VecSize = Track->BarriersDownVector.size();
3681 
3682  Utilities->SaveFileInt(OutFile, VecSize);
3683  for(int x = 0; x < VecSize; x++)
3684  {
3686  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3687  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3688  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3689  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3690  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3691  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3692  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3693  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3694  }
3695  Utilities->CallLogPop(1963);
3696 }
3697 
3698 // ---------------------------------------------------------------------------
3699 
3700 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3701 {
3702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3703  int VecSize = Track->ChangingLCVector.size();
3704 
3705  Utilities->SaveFileInt(OutFile, VecSize);
3706  for(int x = 0; x < VecSize; x++)
3707  {
3709  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3710  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3711  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3712  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3713  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3714  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3715  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3716  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3717  }
3718  Utilities->CallLogPop(1980);
3719 }
3720 
3721 // ---------------------------------------------------------------------------
3722 
3723 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3724 {
3725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3726  int VecSize = Utilities->LoadFileInt(VecFile);
3727 
3728  for(int x = 0; x < VecSize; x++)
3729  {
3730  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3731  {
3732  Utilities->CallLogPop(1970);
3733  return(false);
3734  }
3735  if(!Utilities->CheckFileBool(VecFile))
3736  {
3737  Utilities->CallLogPop(1971);
3738  return(false);
3739  }
3740  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3741  {
3742  Utilities->CallLogPop(1972);
3743  return(false);
3744  }
3745  if(!Utilities->CheckFileDouble(VecFile))
3746  {
3747  Utilities->CallLogPop(1973);
3748  return(false);
3749  }
3750  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3751  {
3752  Utilities->CallLogPop(1974);
3753  return(false);
3754  }
3755  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3756  {
3757  Utilities->CallLogPop(1975);
3758  return(false);
3759  }
3760  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3761  {
3762  Utilities->CallLogPop(1976);
3763  return(false);
3764  }
3765  if(!Utilities->CheckFileDouble(VecFile))
3766  {
3767  Utilities->CallLogPop(1977);
3768  return(false);
3769  }
3770  }
3771  Utilities->CallLogPop(1978);
3772  return(true);
3773 }
3774 
3775 // ---------------------------------------------------------------------------
3776 
3777 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3778 {
3779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3780  int VecSize = Utilities->LoadFileInt(VecFile);
3781 
3782  for(int x = 0; x < VecSize; x++)
3783  {
3784  TActiveLevelCrossing TALC;
3785  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3786  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3787  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3788  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3789  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3790  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3791  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3792  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3793  BarriersDownVector.push_back(TALC);
3794  }
3795  Utilities->CallLogPop(1979);
3796 }
3797 
3798 // ---------------------------------------------------------------------------
3799 
3800 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3801 /*
3802  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3803  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3804  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3805 */
3806 {
3807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3808  TTrackElement Next;
3809 
3810 // Disp->ClearDisplay();
3812  while(ReturnNextInactiveTrackElement(0, Next))
3813  {
3814  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3815  {
3816  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3817  {
3818  // only plot if on screen, to save time
3819  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3821  {
3822  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3823  }
3824  }
3825  }
3826  }
3827 
3828 // TextHandler->RebuildFromTextVector(, Disp); // plot text after inactives so can have text on stations etc //moved below at v2.20.3
3829 
3830  NextTrackElementPtr = TrackVector.begin();
3831  while(ReturnNextTrackElement(0, Next))
3832  {
3833  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3834  {
3835  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3837  {
3838  if(Next.TrackType == Points)
3839  {
3840  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3841  }
3842  else if(Next.TrackType == SignalPost)
3843  {
3844  PlotSignal(9, Next, Disp);
3845  }
3846  else if(Next.TrackType == GapJump)
3847  {
3848  PlotGap(0, Next, Disp);
3849  }
3850  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3851  {
3852  PlotContinuation(0, Next, Disp);
3853  }
3854  else
3855  {
3856  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3857  }
3858  }
3859  }
3860  }
3861 
3862  if(BothPointFilletsAndBasicLCs)
3863  {
3865  while(ReturnNextInactiveTrackElement(4, Next))
3866  {
3867  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3868  {
3869  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3870  {
3871  // only plot if on screen, to save time, & OK as plotting one by one here
3872  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3874  {
3875  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3876  {
3877  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3878  }
3879  else
3880  {
3881  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3882  }
3883  }
3884  }
3885  }
3886  }
3887  }
3888 
3889  TextHandler->RebuildFromTextVector(1, Disp); // plot text after all else so visible over stations/track etc. //moved from above at v2.20.3
3890  Disp->Update();
3891  Utilities->CallLogPop(468);
3892 }
3893 
3894 // ---------------------------------------------------------------------------
3895 
3896 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3897 {
3898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3899  if(UserGraphicVector.empty())
3900  {
3901  Utilities->CallLogPop(2175);
3902  return;
3903  }
3904  TUserGraphicItem UGI;
3905 
3906  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3907  {
3908  UGI = UserGraphicVectorAt(4, x);
3909  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3910  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3911  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3912  {
3913  Disp->PlotAndAddUserGraphic(0, UGI);
3914  }
3915  }
3916  Disp->Update();
3917  Utilities->CallLogPop(2176);
3918 }
3919 
3920 // ---------------------------------------------------------------------------
3921 
3922 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3923 /*
3924  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3925 */
3926 {
3927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3928 // need to change graphics back to black on white if have a dark background
3929  TColor OldTransparentColour = Utilities->clTransparent;
3930 
3932  {
3933  Utilities->clTransparent = TColor(0xFFFFFF); // white
3936  }
3937  TTrackElement Next;
3938 
3939  Bitmap->Canvas->CopyMode = cmSrcCopy;
3941  Graphics::TBitmap *GraphicOutput;
3942 
3943  while(ReturnNextInactiveTrackElement(2, Next))
3944  {
3945  GraphicOutput = Next.GraphicPtr;
3946  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3947  {
3948  if(Next.LocationName == "") // plot as named or unnamed (striped)
3949  {
3950  // default is not striped
3951  switch(Next.SpeedTag)
3952  {
3953  case 76: // t platform
3954  GraphicOutput = RailGraphics->gl76Striped;
3955  break;
3956 
3957  case 77: // h platform
3958  GraphicOutput = RailGraphics->bm77Striped;
3959  break;
3960 
3961  case 78: // v platform
3962  GraphicOutput = RailGraphics->bm78Striped;
3963  break;
3964 
3965  case 79: // r platform
3966  GraphicOutput = RailGraphics->gl79Striped;
3967  break;
3968 
3969  case 96: // concourse
3970  GraphicOutput = RailGraphics->ConcourseStriped;
3971  break;
3972 
3973  case 129: // v footbridge
3974  GraphicOutput = RailGraphics->gl129Striped;
3975  break;
3976 
3977  case 130: // h footbridge
3978  GraphicOutput = RailGraphics->gl130Striped;
3979  break;
3980 
3981  case 131: // non-station named loc
3982  GraphicOutput = RailGraphics->bmNameStriped;
3983  break;
3984 
3985  case 145: // v underpass
3986  GraphicOutput = RailGraphics->gl145Striped;
3987  break;
3988 
3989  case 146: // h underpass
3990  GraphicOutput = RailGraphics->gl146Striped;
3991  break;
3992 
3993  default:
3994  GraphicOutput = Next.GraphicPtr;
3995  break;
3996  }
3997  }
3998  if(Next.SpeedTag == 144) // level crossing
3999  {
4000  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
4001  {
4002  GraphicOutput = RailGraphics->LCBothVer;
4003  }
4004  else
4005  {
4006  GraphicOutput = RailGraphics->LCBothHor;
4007  }
4008  }
4009  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4010  }
4011  }
4012 
4013  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4014 
4015 
4016  NextTrackElementPtr = TrackVector.begin();
4017  while(ReturnNextTrackElement(2, Next))
4018  {
4019  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4020  {
4021  if(Next.TrackType == Points) // plot both fillets
4022  {
4023  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4024  if(Next.SpeedTag < 28)
4025  {
4026  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4028  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4030  }
4031  else if(Next.SpeedTag < 132)
4032  {
4033  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4034  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4035  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4036  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4037  }
4038  else
4039  {
4040  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4041  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4042  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4043  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4044  }
4045  }
4046  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4047  {
4048  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4049  {
4050  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4051  }
4052  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4053  {
4054  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4055  }
4056  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4057  {
4058  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4059  }
4060  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4061  {
4062  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4063  }
4064  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4065  {
4066  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4067  }
4068  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4069  {
4070  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4071  }
4072  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4073  {
4074  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4075  }
4076  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4077  {
4078  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4079  }
4080  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4081  {
4082  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4083  }
4084  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4085  {
4086  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4087  }
4088  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4089  {
4090  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4091  }
4092  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4093  {
4094  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4095  }
4096  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4097  {
4098  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4099  }
4100  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4101  {
4102  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4103  }
4104  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4105  {
4106  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4107  }
4108  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4109  {
4110  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4111  }
4112  }
4113  // below added for version 0.6, only stop signals to be drawn
4114  else if(Next.TrackType == SignalPost)
4115  {
4116  for(int x = 0; x < 40; x++)
4117  {
4118  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4119  {
4120  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4121  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4122  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4123  int HOffset = 0;
4124  if(Next.SpeedTag > 73)
4125  {
4126  HOffset = 5;
4127  }
4128  else if(Next.SpeedTag == 71)
4129  {
4130  HOffset = 9;
4131  }
4132  int VOffset = 0;
4133  if(Next.SpeedTag == 69)
4134  {
4135  VOffset = 9;
4136  }
4137  else if(Next.SpeedTag == 72)
4138  {
4139  VOffset = 5;
4140  }
4141  else if(Next.SpeedTag == 74)
4142  {
4143  VOffset = 5;
4144  }
4145  Graphics::TBitmap *GraphicPtr;
4146  if(Next.SpeedTag > 71)
4147  {
4148  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4149  }
4150  else if(Next.SpeedTag < 70)
4151  {
4152  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4153  }
4154  else
4155  {
4156  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4157  }
4158  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4159  // plot special signal platform if present
4160  Graphics::TBitmap* SignalPlatformGraphic;
4161  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4162  {
4163  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4164  }
4165  // now plot signal (double yellow overwrites most of signal platform if present)
4166  // below amended for version 0.6
4168  {
4169  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4170  }
4171  else if(Next.SigAspect == TTrackElement::TwoAspect)
4172  {
4173  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4174  }
4175  else if(Next.SigAspect == TTrackElement::GroundSignal)
4176  {
4177  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4178  }
4179  else // 4 aspect
4180  {
4181  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4182  }
4183  break;
4184  }
4185  }
4186  }
4187  else
4188  {
4189  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4190  }
4191  }
4192  }
4193  if(OldTransparentColour != clB5G5R5)
4194  {
4195  Utilities->clTransparent = OldTransparentColour; // restore
4198  }
4199  Utilities->CallLogPop(1533);
4200 }
4201 
4202 // ---------------------------------------------------------------------------
4203 
4204 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4205 {
4206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4207  if(UserGraphicVector.empty())
4208  {
4209  Utilities->CallLogPop(2192);
4210  return;
4211  }
4212  else
4213  {
4214  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4215  {
4216  Bitmap->Canvas->CopyMode = cmSrcCopy;
4217  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4218  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4219  }
4220  }
4221  Utilities->CallLogPop(2193);
4222 }
4223 
4224 // ---------------------------------------------------------------------------
4225 
4226 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4227 /*
4228  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4229  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4230 */
4231 {
4232  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4233 // need to change graphics back to black on white if have a dark background
4234  TColor OldTransparentColour = Utilities->clTransparent;
4235 
4237  {
4238  Utilities->clTransparent = TColor(0xFFFFFF); // white
4241  }
4242  TTrackElement Next;
4243 
4244  Bitmap->Canvas->CopyMode = cmSrcCopy;
4246  Graphics::TBitmap *GraphicOutput;
4247 
4248  while(ReturnNextInactiveTrackElement(3, Next))
4249  {
4250  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4251  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4252  {
4253  if(Next.SpeedTag == 144) // level crossing
4254  {
4255  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4256  if(BaseElement == 1) // hor element
4257  {
4258  if(Next.Attribute == 1) // open to trains
4259  {
4260  GraphicOutput = RailGraphics->LCBothHor;
4261  }
4262  else // plot as closed to trains if in any other state
4263  {
4264  GraphicOutput = RailGraphics->LCBothVer;
4265  }
4266  }
4267  else // vert element
4268  {
4269  if(Next.Attribute == 1) // open to trains
4270  {
4271  GraphicOutput = RailGraphics->LCBothVer;
4272  }
4273  else // plot as closed to trains if in any other state
4274  {
4275  GraphicOutput = RailGraphics->LCBothHor;
4276  }
4277  }
4278  }
4279  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4280  }
4281  }
4282 
4283  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4284 
4285  NextTrackElementPtr = TrackVector.begin();
4286  while(ReturnNextTrackElement(3, Next))
4287  {
4288  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4289  {
4290  if(Next.TrackType == Points) // plot active fillet
4291  {
4292  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4293  if(Next.SpeedTag < 28)
4294  {
4295  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4297  }
4298  else if(Next.SpeedTag < 132)
4299  {
4300  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4302  }
4303  else
4304  {
4305  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4307  }
4308  if(Next.Failed) //added at v2.13.0
4309  {
4310  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4312  }
4313 
4314  }
4315  else if(Next.TrackType == GapJump) // plot as connected
4316  {
4317  if(Next.SpeedTag == 88)
4318  {
4319  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4320  }
4321  else if(Next.SpeedTag == 89)
4322  {
4323  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4324  }
4325  else if(Next.SpeedTag == 90)
4326  {
4327  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4328  }
4329  else if(Next.SpeedTag == 91)
4330  {
4331  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4332  }
4333  else if(Next.SpeedTag == 92)
4334  {
4335  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4336  }
4337  else if(Next.SpeedTag == 93)
4338  {
4339  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4340  }
4341  else if(Next.SpeedTag == 94)
4342  {
4343  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4344  }
4345  else if(Next.SpeedTag == 95)
4346  {
4347  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4348  }
4349  }
4350  else if(Next.TrackType == SignalPost) //plot in correct colour
4351  {
4352  for(int x = 0; x < 40; x++)
4353  {
4354  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4355  {
4356  //plot blank first, then plot platform if present - (always not striped for operating railway)
4357  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4358  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4359  int HOffset = 0;
4360  if(Next.SpeedTag > 73)
4361  {
4362  HOffset = 5;
4363  }
4364  else if(Next.SpeedTag == 71)
4365  {
4366  HOffset = 9;
4367  }
4368  int VOffset = 0;
4369  if(Next.SpeedTag == 69)
4370  {
4371  VOffset = 9;
4372  }
4373  else if(Next.SpeedTag == 72)
4374  {
4375  VOffset = 5;
4376  }
4377  else if(Next.SpeedTag == 74)
4378  {
4379  VOffset = 5;
4380  }
4381  Graphics::TBitmap *GraphicPtr;
4382  if(Next.SpeedTag > 71)
4383  {
4384  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4385  }
4386  else if(Next.SpeedTag < 70)
4387  {
4388  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4389  }
4390  else
4391  {
4392  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4393  }
4394  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4395  // plot special signal platform if present
4396  Graphics::TBitmap* SignalPlatformGraphic;
4397  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4400  }
4401  if(!Next.Failed)
4402  {
4403  // now plot signal (double yellow overwrites most of signal platform if present)
4404  // below amended for version 0.6
4406  {
4407  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4408  }
4409  else if(Next.SigAspect == TTrackElement::TwoAspect)
4410  {
4411  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4412  }
4413  else if(Next.SigAspect == TTrackElement::GroundSignal)
4414  {
4415  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4416  }
4417  else // 4 aspect
4418  {
4419  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4420  }
4421  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4422  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4423  {
4424  if(Next.SpeedTag == 68)
4425  {
4426  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4427  }
4428  if(Next.SpeedTag == 69)
4429  {
4430  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4431  }
4432  if(Next.SpeedTag == 70)
4433  {
4434  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4435  }
4436  if(Next.SpeedTag == 71)
4437  {
4438  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4439  }
4440  if(Next.SpeedTag == 72)
4441  {
4442  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4443  }
4444  if(Next.SpeedTag == 73)
4445  {
4446  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4447  }
4448  if(Next.SpeedTag == 74)
4449  {
4450  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4451  }
4452  if(Next.SpeedTag == 75)
4453  {
4454  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4455  }
4456  }
4457  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4458  {
4459  for(int x = 0; x < 40; x++)
4460  {
4461  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4462  {
4463  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4464  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4465  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4466  // plot special signal platform if present
4467  Graphics::TBitmap* SignalPlatformGraphic;
4468  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4469  {
4470  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4471  }
4472  // now plot signal
4473  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4474  break;
4475  }
4476  }
4477  }
4478  break;
4479  }
4480  else //added at v2.13.0
4481  {
4483  {
4484  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4485  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4486  }
4487  else
4488  {
4489  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4490  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4491  }
4492  break;
4493  }
4494  }
4495  }
4496  }
4497  else
4498  {
4499  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4500  if(Next.Failed) //added at v2.13.0
4501  {
4502  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4504  }
4505  }
4506  }
4507  }
4508  if(OldTransparentColour != clB5G5R5)
4509  {
4510  Utilities->clTransparent = OldTransparentColour; // restore
4513  }
4514  Utilities->CallLogPop(1701);
4515 }
4516 
4517 // ---------------------------------------------------------------------------
4518 
4519 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4520 {
4521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4522  for(unsigned int x = 0; x < TrackVector.size(); x++)
4523  {
4524  if(TrackElementAt(1093, x).TrackType == GapJump)
4525  {
4526  if(TrackElementAt(1094, x).Conn[0] > -1)
4527  {
4528  continue; // to next 'x' value as this element has already been set
4529  }
4530  // here if identify a GapJump element not yet set
4531  GapPos = x;
4532  GapHLoc = TrackElementAt(1095, x).HLoc;
4533  GapVLoc = TrackElementAt(1096, x).VLoc;
4534  // highlight it
4536  Utilities->CallLogPop(469);
4537  return(true);
4538  }
4539  }
4540  Utilities->CallLogPop(470);
4541  return(false);
4542 }
4543 
4544 // ---------------------------------------------------------------------------
4545 
4546 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4547 {
4548  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4549  AnsiString(VLoc));
4550  int Position;
4551  TTrackElement TrackElement;
4552 
4553  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4554  {
4555  Utilities->CallLogPop(471);
4556  return(false); // not found
4557  }
4558  if(TrackElement.TrackType != GapJump)
4559  {
4560  Utilities->CallLogPop(472);
4561  return(false); // found something but not a gap
4562  }
4563  if(Position == GapPos)
4564  {
4565  Utilities->CallLogPop(473);
4566  return(false); // selected original gap
4567  }
4568  if(TrackElementAt(1097, Position).Conn[0] != -1)
4569  {
4570  Utilities->CallLogPop(474);
4571  return(false); // already selected
4572  }
4573  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4574  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4575  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4576  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4577 // now highlight the selected location
4578  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4579  Utilities->CallLogPop(475);
4580  return(true);
4581 }
4582 
4583 // ---------------------------------------------------------------------------
4584 
4585 bool TTrack::GapsUnset(int Caller)
4586 // returns true if there are gaps and any are unset
4587 {
4588  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4589  if(TrackVector.size() == 0)
4590  {
4591  Utilities->CallLogPop(476);
4592  return(false);
4593  }
4594  for(unsigned int x = 0; x < TrackVector.size(); x++)
4595  {
4596  if(TrackElementAt(1102, x).TrackType == GapJump)
4597  {
4598  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4599  {
4600  Utilities->CallLogPop(477);
4601  return(true);
4602  }
4603  else // set, but may not have matching element, or that element may not be set
4604  {
4605  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4606  // check that the element pointed to by the gap link is a GapJump
4607  {
4608  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4609  Utilities->CallLogPop(1137);
4610  return(false);
4611  }
4612 // here if gap connection is itself a GapJump
4613  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4614  // check that the element pointed to by the gap link is a GapJump & that its gap link
4615  // points back to 'x'
4616  {
4617  Utilities->CallLogPop(478);
4618  return(true);
4619  }
4620 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4621  }
4622  } // if(TrackElementAt(, x).TrackType == GapJump)
4623 
4624  } // for x...
4625  Utilities->CallLogPop(479);
4626  return(false);
4627 }
4628 
4629 // ---------------------------------------------------------------------------
4630 
4631 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4632 {
4633  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4634  for(unsigned int x = 0; x < TrackVector.size(); x++)
4635  {
4636  if(TrackElementAt(1110, x).TrackType == GapJump)
4637  {
4638  Utilities->CallLogPop(1105);
4639  return(false);
4640  }
4641  }
4642  Utilities->CallLogPop(1106);
4643  return(true);
4644 }
4645 
4646 // ---------------------------------------------------------------------------
4647 
4648 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4649 {
4650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4651  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4652  {
4653  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4654  {
4655  Utilities->CallLogPop(1107);
4656  return(false);
4657  }
4658  }
4659  for(unsigned int x = 0; x < TrackVector.size(); x++)
4660  {
4661  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4662  {
4663  Utilities->CallLogPop(1108);
4664  return(false);
4665  }
4666  }
4667  Utilities->CallLogPop(1109);
4668  return(true);
4669 }
4670 
4671 // ---------------------------------------------------------------------------
4672 
4674 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4675 // returns false otherwise or if there are no NamedLocationElements
4676 {
4677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4678  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4679  {
4680  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4681  {
4682  if(InactiveTrackElementAt(139, x).LocationName == "")
4683  {
4684  Utilities->CallLogPop(1110);
4685  return(true);
4686  }
4687  }
4688  }
4689  for(unsigned int x = 0; x < TrackVector.size(); x++)
4690  {
4691  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4692  {
4693  if(TrackElementAt(1113, x).LocationName == "")
4694  {
4695  Utilities->CallLogPop(1111);
4696  return(true);
4697  }
4698  }
4699  }
4700  Utilities->CallLogPop(1112);
4701  return(false);
4702 }
4703 
4704 // ---------------------------------------------------------------------------
4705 
4706 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4707 {
4708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4709  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4710  Utilities->CallLogPop(480);
4711 }
4712 
4713 // ---------------------------------------------------------------------------
4714 
4716 {
4717  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4718  if(TrackVector.size() == 0)
4719  {
4720  Utilities->CallLogPop(481);
4721  return;
4722  }
4723  for(unsigned int x = 0; x < TrackVector.size(); x++)
4724  {
4725  if(TrackElementAt(1114, x).TrackType == GapJump)
4726  {
4727  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4728  {
4729  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4730  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4731  {
4732  TrackElementAt(1118, x).Conn[0] = -1;
4733  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4734  continue; // to next 'x'
4735  }
4736 // here if gap connection is itself a GapJump
4737  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4738  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4739  // if not clear Conns & CLks
4740  {
4741  TrackElementAt(1121, x).Conn[0] = -1;
4742  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4743  continue; // to next 'x'
4744  }
4745 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4746 // hence no more action needed on these Conns & CLks
4747  }
4748  } // else //gap jump
4749 
4750  } // for x...
4751 // throw Exception("Test Exception");//test
4752  Utilities->CallLogPop(482);
4753 }
4754 
4755 // ---------------------------------------------------------------------------
4756 
4757 void TTrack::ResetSignals(int Caller)
4758 {
4759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4760  for(unsigned int x = 0; x < TrackVector.size(); x++)
4761  {
4762  if(TrackElementAt(1123, x).TrackType == SignalPost)
4763  {
4764  TrackElementAt(1124, x).Attribute = 0;
4765  TrackElementAt(1514, x).Failed = false;
4766  TrackElementAt(1682, x).CallingOnSet = false; //added at v2.20.3 to clear position light signals
4767  }
4768  }
4769  FailedSignalsVector.clear();
4770  Utilities->CallLogPop(483);
4771 }
4772 
4773 // ---------------------------------------------------------------------------
4774 
4775 void TTrack::ResetPoints(int Caller)
4776 {
4777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4778  for(unsigned int x = 0; x < TrackVector.size(); x++)
4779  {
4780  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4781  {
4782  TrackElementAt(1126, x).Attribute = 0;
4783  TrackElementAt(1515, x).Failed = false;
4786  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4787  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4788  }
4789  }
4790  FailedPointsVector.clear();
4791  Utilities->CallLogPop(484);
4792 }
4793 
4794 // ---------------------------------------------------------------------------
4795 
4796 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4797 {
4798  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4799  for(unsigned int x = 0; x < TrackVector.size(); x++)
4800  {
4801  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4802  {
4803  TrackElementAt(1556, x).Failed = false;
4805  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4806  }
4807  }
4808  TSRVector.clear();
4809  Utilities->CallLogPop(2550);
4810 }
4811 
4812 // ---------------------------------------------------------------------------
4813 
4814 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4815 {
4816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4817  if(TrackVector.empty())
4818  {
4819  TrackMap.clear();
4820  Utilities->CallLogPop(485);
4821  return(true);
4822  }
4823 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4824  THVPair TrackMapKeyPair;
4825 
4826  NewVector.clear();
4827  TTrackMapIterator TrackMapPtr;
4828 
4829  if(!TrackMap.empty())
4830  {
4831  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4832  {
4833  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4834  }
4835  }
4836  if(NewVector.size() != TrackMap.size())
4837  {
4838  throw Exception("Error - Map & Vector different sizes");
4839  }
4840  unsigned int NonZeroCount = 0;
4841 
4842  for(unsigned int x = 0; x < TrackVector.size(); x++)
4843  {
4844  if(TrackElementAt(1127, x).TrackType != Erase)
4845  {
4846  NonZeroCount++;
4847  }
4848  }
4849  if(NewVector.size() != NonZeroCount)
4850  {
4851  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4852  }
4854  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4855  TTrackMapEntry TrackMapEntry;
4856 
4857  for(unsigned int x = 0; x < TrackVector.size(); x++)
4858  {
4859  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4860  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4861  TrackMapEntry.first = TrackMapKeyPair;
4862  TrackMapEntry.second = x;
4863  if(!(TrackMap.insert(TrackMapEntry).second))
4864  {
4865  throw Exception("Error - map insertion failure, TrackVector in error");
4866  }
4867  }
4868 // All track now relocated in TrackVector, reset all Conns & CLks
4869  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4870  {
4871  for(unsigned int y = 0; y < 4; y++)
4872  {
4873  TrackElementAt(1130, x).Conn[y] = -1;
4874  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4875  }
4876  }
4877  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4878  CheckMapAndTrack(4); // test
4879  CheckMapAndInactiveTrack(4); // test
4880  CheckLocationNameMultiMap(8); // test
4881  if(!ResetGapsFromGapMap(1))
4882  {
4883  Utilities->CallLogPop(489);
4884  return(false);
4885  }
4886  Utilities->CallLogPop(490);
4887  return(true);
4888 }
4889 
4890 // ---------------------------------------------------------------------------
4891 
4892 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4893 {
4894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4895  GapMap.clear();
4896  THVPair GapMapKeyPair, GapMapValuePair;
4897  TGapMapEntry GapMapEntry;
4898 
4899  for(unsigned int x = 0; x < TrackVector.size(); x++)
4900  {
4901  if(TrackElementAt(1132, x).TrackType == GapJump)
4902  {
4903  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4904  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4905  GapMapEntry.first = GapMapKeyPair;
4906  if(TrackElementAt(1135, x).Conn[0] == -1)
4907  {
4908  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4909  }
4910  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4911  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4912  GapMapEntry.second = GapMapValuePair;
4913  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4914  {
4915  GapMap.insert(GapMapEntry);
4916  }
4917  }
4918  }
4919  Utilities->CallLogPop(492);
4920 }
4921 
4922 // ---------------------------------------------------------------------------
4923 
4924 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4925 {
4926  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4927 
4928 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4929  LocError = false;
4930  bool TrackElementPositionsOK = true;
4931 
4932  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4933  {
4934  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4935  {
4936  continue; // skip blank elements
4937  }
4938 // check footcrossing linkages
4939  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4940  {
4941  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4942  {
4943  ShowMessage(
4944  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4945  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4946  "can't connect to an underpass or vice versa)");
4947  HLoc = TrackElementAt(1141, x).HLoc;
4948  VLoc = TrackElementAt(1142, x).VLoc;
4949  LocError = true;
4950  Utilities->CallLogPop(493);
4951  return(false);
4952  }
4953  }
4954  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4955  {
4956  if(TrackElementAt(1143, x).Link[y] <= 0)
4957  {
4958  continue; // no link
4959  }
4960  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4961  {
4962  continue; // buffer
4963  }
4964  if(TrackElementAt(1146, x).Config[y] == Gap)
4965  {
4966  continue; // gaps set later from GapMap
4967  }
4968  // get required H & V for track element joining link 'y'
4969  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4970  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4971  // find track element if present
4972  bool ConnectionFoundFlag;
4973  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4974  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4975  {
4976  ShowMessage("Can't have a track element adjacent to a continuation exit");
4977  HLoc = TrackElementAt(1152, x).HLoc;
4978  VLoc = TrackElementAt(1153, x).VLoc;
4979  LocError = true;
4980  if(FinalCall)
4981  {
4982  throw Exception("Error in final track linkage - continuation adjacent to another element");
4983  }
4984  Utilities->CallLogPop(1539);
4985  return(false);
4986  }
4987  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4988  {
4989  continue;
4990  }
4991  if(ConnectionFoundFlag)
4992  {
4993  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4994  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4995 
4996  bool ExitSignal = false;
4997  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
4998  {
4999  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
5000  {
5001  ExitSignal = true;
5002  }
5003  }
5004  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5005  {
5006  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5007  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5008  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5009  TrackElementPositionsOK = false;
5010  }
5011  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5012  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5013  {
5014  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5015  // need room for a train (2 elements) without fouling points or signals
5016  TrackElementPositionsOK = false;
5017  }
5018  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5019  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5020  {
5021  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5022  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5023  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5024  // be named but needs the adjacent element named too
5025  TrackElementPositionsOK = false;
5026  }
5027  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5028  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5029  {
5030  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5031  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5032  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5033  TrackElementPositionsOK = false;
5034  }
5035 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5036 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
5037  {
5038  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5039  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5040  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5041  TrackElementPositionsOK = false;
5042  }*/
5043  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5044  {
5045  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5046  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5047  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5048  TrackElementPositionsOK = false;
5049  }
5050  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5051  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5052  {
5053  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5054  TrackElementPositionsOK = false;
5055  }
5056  // if failed then set the invert values for the offending element
5057  if(!TrackElementPositionsOK)
5058  {
5059  HLoc = TrackElementAt(1183, x).HLoc;
5060  VLoc = TrackElementAt(1184, x).VLoc;
5061  LocError = true;
5062  if(FinalCall)
5063  {
5064  throw Exception("Error in track element positions in FinalCall");
5065  }
5066  Utilities->CallLogPop(494);
5067  return(false);
5068  }
5069  }
5070  // no 'else' here, if there's no link then will be picked up in 2nd pass
5071  }
5072  } // for(unsigned int x=0;x<TrackVector.size();x++)
5073 
5074 
5075 //2nd pass - looking for missing connections
5076  LocError = false;
5077  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5078  {
5079  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5080  {
5081  continue; // skip blank elements
5082  }
5083  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5084  {
5085  if(TrackElementAt(1440, x).Link[y] <= 0)
5086  {
5087  continue; // no link
5088  }
5089  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5090  {
5091  continue; // buffer
5092  }
5093  if(TrackElementAt(1443, x).Config[y] == Gap)
5094  {
5095  continue; // gaps set later from GapMap
5096  }
5097  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5098  {
5099  continue; //continuation
5100  }
5101  // get required H & V for track element joining link 'y'
5102  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5103  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5104  // find track element if present
5105  bool ConnectionFoundFlag;
5106  bool LinkMatchFound = false;
5107  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5108  // if there isn't a connection set the invert values for the offending element
5109  if(ConnectionFoundFlag) //set the ConnLinkPos values
5110  {
5111  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5112  {
5113  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5114  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5115  {
5116  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5117  LinkMatchFound = true;
5118  break; //can only match 1 so can break
5119  }
5120  }
5121  if(!LinkMatchFound)
5122  {
5123  HLoc = TrackElementAt(1446, x).HLoc;
5124  VLoc = TrackElementAt(1447, x).VLoc;
5125  LocError = true;
5126  if(FinalCall)
5127  {
5128  throw Exception("Error in final track linkage - - no matching link found");
5129  }
5130  Utilities->CallLogPop(495);
5131  return(false);
5132  }
5133  }
5134  else //error
5135  {
5136  HLoc = TrackElementAt(1185, x).HLoc;
5137  VLoc = TrackElementAt(1186, x).VLoc;
5138  LocError = true;
5139  if(FinalCall)
5140  {
5141  throw Exception("Error in final track linkage - connection not found");
5142  }
5143  Utilities->CallLogPop(2443);
5144  return(false);
5145  }
5146  }
5147  }
5148 //end of 2nd pass
5149 
5150  if(FinalCall)
5151  {
5154  }
5155 
5156 // confirmatiory checks that all ok - or throw error
5157  bool ConnErrorFlag = false;
5158 
5159  for(unsigned int x = 0; x < TrackVector.size(); x++)
5160  {
5161  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5162  {
5163  ConnErrorFlag = true;
5164  }
5165  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5166  {
5167  ConnErrorFlag = true;
5168  }
5169  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5170  {
5171  ConnErrorFlag = true;
5172  }
5173  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5174  {
5175  ConnErrorFlag = true;
5176  }
5177  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5178  {
5179  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5180  {
5181  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5182  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5183  {
5184  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5185  }
5186  }
5187  }
5188  }
5189  if(ConnErrorFlag)
5190  {
5191  if(FinalCall)
5192  {
5193  throw Exception("ConnError in LinkTrack - Final");
5194  }
5195  else
5196  {
5197  throw Exception("ConnError in LinkTrack - Precheck");
5198  }
5199  }
5200  bool CLkErrorFlag = false;
5201 
5202  for(unsigned int x = 0; x < TrackVector.size(); x++)
5203  {
5204  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5205  {
5206  CLkErrorFlag = true;
5207  }
5208  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5209  {
5210  CLkErrorFlag = true;
5211  }
5212  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5213  {
5214  CLkErrorFlag = true;
5215  }
5216  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5217  {
5218  CLkErrorFlag = true;
5219  }
5220  }
5221 
5222  if(CLkErrorFlag)
5223  {
5224  if(FinalCall)
5225  {
5226  throw Exception("CLkError in LinkTrack - Final");
5227  }
5228  else
5229  {
5230  throw Exception("CLkError in LinkTrack - Precheck");
5231  }
5232  }
5233 
5234 // set element lengths to min of 10m
5235  for(unsigned int x = 0; x < TrackVector.size(); x++)
5236  {
5237  if(TrackElementAt(1214, x).TrackType == Erase)
5238  {
5239  continue; // skip blank elements
5240  }
5241  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5242  {
5243  TrackElementAt(1216, x).Length01 = 10;
5244  }
5245  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5246  {
5247  TrackElementAt(1219, x).Length23 = 10;
5248  }
5249  }
5250 
5251  if(FinalCall) // ONLY at FinalCall, no point calling twice
5252  {
5253  CalcHLocMinEtc(3);
5254  }
5255 
5256  Utilities->CallLogPop(497);
5257  return(true);
5258 }
5259 
5260 // ---------------------------------------------------------------------------
5261 
5262 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5263 {
5264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5265  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5266  {
5267  if(TrackElementAt(1220, x).TrackType == Erase)
5268  {
5269  continue; // skip blank elements
5270 
5271  }
5272 // check footcrossing linkages
5273  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5274  {
5275  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5276  {
5277  Utilities->CallLogPop(1127);
5278  return(false);
5279  }
5280  }
5281  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5282  {
5283  if(TrackElementAt(1223, x).Link[y] <= 0)
5284  {
5285  continue; // no link
5286  }
5287  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5288  {
5289  continue; // buffer
5290  }
5291  if(TrackElementAt(1226, x).Config[y] == Gap)
5292  {
5293  continue; // gaps set later from GapMap
5294 
5295  }
5296  // get required H & V for track element joining link 'y'
5297  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5298  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5299  // find track element if present
5300  bool ConnectionFoundFlag;
5301  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5302  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5303  {
5304  if(FinalCall)
5305  {
5306  throw Exception("Error in final track linkage - continuation adjacent to another element");
5307  }
5308  Utilities->CallLogPop(1540);
5309  return(false);
5310  }
5311  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5312  {
5313  continue;
5314  }
5315  if(ConnectionFoundFlag)
5316  {
5317  TrackElementAt(1234, x).Conn[y] = VecPos;
5318  bool LinkFoundFlag = false;
5319  // find connecting link in the newly found track element if there is one & make checks
5320  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5321  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5322  {
5323  Utilities->CallLogPop(1541);
5324  return(false);
5325  }
5326  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5327  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5328  {
5329  Utilities->CallLogPop(1542);
5330  return(false);
5331  }
5332  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5333  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5334  {
5335  Utilities->CallLogPop(1543);
5336  return(false);
5337  }
5338  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5339  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5340  {
5341  Utilities->CallLogPop(1981);
5342  return(false);
5343  }
5344 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5345  else if(TrackElementAt(, x).TrackType == Continuation)
5346  {
5347  int H = TrackElementAt(, x).HLoc;
5348  int V = TrackElementAt(, x).VLoc;
5349  bool FoundFlag = false;
5350  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5351  if(FoundFlag)
5352  {
5353  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5354  {
5355  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5356  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5357  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5358  if(FoundFlag)
5359  {
5360  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5361  {
5362  Utilities->CallLogPop();
5363  return false;
5364  }
5365  }
5366  else
5367  {
5368  Utilities->CallLogPop();
5369  return false;
5370  }
5371  }
5372  }
5373  }
5374 */
5375  for(unsigned int a = 0; a < 4; a++)
5376  {
5377  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5378  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5379  {
5380  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5381  // note - this ensures that if the connecting element is a leading point
5382  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5383  // (Points have the same link value for both [0] and [2])
5384  LinkFoundFlag = true;
5385  break; // stop after first find or will find later link for leading point
5386  }
5387  }
5388  if(!LinkFoundFlag)
5389  {
5390  if(FinalCall)
5391  {
5392  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5393  }
5394  Utilities->CallLogPop(1128);
5395  return(false);
5396  }
5397  }
5398  else // if(ConnectionFoundFlag)
5399  {
5400  if(FinalCall)
5401  {
5402  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5403  }
5404  Utilities->CallLogPop(1129);
5405  return(false);
5406  }
5407  }
5408  } // for(unsigned int x=0;x<TrackVector.size();x++)
5409 
5410  if(FinalCall)
5411  {
5414  }
5415 // final check
5416  bool ConnErrorFlag = false;
5417 
5418  for(unsigned int x = 0; x < TrackVector.size(); x++)
5419  {
5420  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5421  {
5422  ConnErrorFlag = true;
5423  }
5424  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5425  {
5426  ConnErrorFlag = true;
5427  }
5428  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5429  {
5430  ConnErrorFlag = true;
5431  }
5432  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5433  {
5434  ConnErrorFlag = true;
5435  }
5436  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5437  {
5438  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5439  {
5440  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5441  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5442  {
5443  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5444  }
5445  }
5446  }
5447  }
5448  if(ConnErrorFlag)
5449  {
5450  if(FinalCall)
5451  {
5452  throw Exception("ConnError in LinkTrack - Final");
5453  }
5454  else
5455  {
5456  throw Exception("ConnError in LinkTrack - Precheck");
5457  }
5458  }
5459  bool CLkErrorFlag = false;
5460 
5461  for(unsigned int x = 0; x < TrackVector.size(); x++)
5462  {
5463  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5464  {
5465  CLkErrorFlag = true;
5466  }
5467  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5468  {
5469  CLkErrorFlag = true;
5470  }
5471  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5472  {
5473  CLkErrorFlag = true;
5474  }
5475  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5476  {
5477  CLkErrorFlag = true;
5478  }
5479  }
5480 
5481  if(CLkErrorFlag)
5482  {
5483  if(FinalCall)
5484  {
5485  throw Exception("CLkError in LinkTrack - Final");
5486  }
5487  else
5488  {
5489  throw Exception("CLkError in LinkTrack - Precheck");
5490  }
5491  }
5492 // set element lengths to min of 10m
5493  for(unsigned int x = 0; x < TrackVector.size(); x++)
5494  {
5495  if(TrackElementAt(1284, x).TrackType == Erase)
5496  {
5497  continue; // skip blank elements
5498  }
5499  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5500  {
5501  TrackElementAt(1286, x).Length01 = 10;
5502  }
5503  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5504  {
5505  TrackElementAt(1289, x).Length23 = 10;
5506  }
5507  }
5508 
5509  if(FinalCall) // ONLY at FinalCall, no point calling twice
5510  {
5511  CalcHLocMinEtc(7);
5512  }
5513  Utilities->CallLogPop(1130);
5514  return(true);
5515 }
5516 
5517 // ---------------------------------------------------------------------------
5518 
5519 bool TTrack::IsTrackLinked(int Caller) // not used any more
5520 {
5521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5522  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5523  {
5524  if(TrackElementAt(1290, x).TrackType == Erase)
5525  {
5526  Utilities->CallLogPop(498);
5527  return(false);
5528  }
5529 // check foot linkages
5530  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5531  {
5532  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5533  {
5534  Utilities->CallLogPop(499);
5535  return(false);
5536  }
5537  }
5538  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5539  {
5540  if(TrackElementAt(1293, x).Link[y] <= 0)
5541  {
5542  continue; // no link
5543  }
5544  if(TrackElementAt(1294, x).Config[y] == End)
5545  {
5546  continue; // buffer or continuation
5547  }
5548  if(TrackElementAt(1295, x).Config[y] == Gap)
5549  {
5550  continue; // gaps set later from GapMap
5551 
5552  }
5553  // get required H & V for track element joining link 'y'
5554  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5555  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5556  // find track element if present
5557  bool ConnectionFoundFlag = false;
5558  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5559  if(ConnectionFoundFlag)
5560  {
5561  TrackElementAt(1300, x).Conn[y] = VecPos;
5562  // find connecting link in the newly found track element if there is one & make buffer check
5563  bool LinkFoundFlag = false;
5564  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5565  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5566  {
5567  Utilities->CallLogPop(500);
5568  return(false);
5569  }
5570  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5571  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5572  {
5573  Utilities->CallLogPop(501);
5574  return(false);
5575  }
5576  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5577  {
5578  Utilities->CallLogPop(502);
5579  return(false);
5580  }
5581  else
5582  {
5583  for(unsigned int a = 0; a < 4; a++)
5584  {
5585  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5586  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5587  {
5588  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5589  // note - this ensures that if the connecting element is a leading point
5590  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5591  // (Points have the same link value for both [0] and [2])
5592  LinkFoundFlag = true;
5593  break; // stop after first find or will find later link for leading point
5594  }
5595  }
5596  }
5597  if(!LinkFoundFlag)
5598  {
5599  Utilities->CallLogPop(503);
5600  return(false);
5601  }
5602  }
5603  else // if(ConnectionFoundFlag)
5604  {
5605  Utilities->CallLogPop(504);
5606  return(false);
5607  }
5608  }
5609  } // for(unsigned int x=0;x<TrackVector.size();x++)
5610 
5611 // final check
5612  bool ConnErrorFlag = false;
5613 
5614  for(unsigned int x = 0; x < TrackVector.size(); x++)
5615  {
5616  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5617  {
5618  ConnErrorFlag = true;
5619  }
5620  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5621  {
5622  ConnErrorFlag = true;
5623  }
5624  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5625  {
5626  ConnErrorFlag = true;
5627  }
5628  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5629  {
5630  ConnErrorFlag = true;
5631  }
5632  }
5633  if(ConnErrorFlag)
5634  {
5635  Utilities->CallLogPop(505);
5636  return(false);
5637  }
5638  bool CLkErrorFlag = false;
5639 
5640  for(unsigned int x = 0; x < TrackVector.size(); x++)
5641  {
5642  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5643  {
5644  CLkErrorFlag = true;
5645  }
5646  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5647  {
5648  CLkErrorFlag = true;
5649  }
5650  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5651  {
5652  CLkErrorFlag = true;
5653  }
5654  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5655  {
5656  CLkErrorFlag = true;
5657  }
5658  }
5659 
5660  if(CLkErrorFlag)
5661  {
5662  Utilities->CallLogPop(506);
5663  return(false);
5664  }
5665  Utilities->CallLogPop(507);
5666  return(true);
5667 }
5668 
5669 // ---------------------------------------------------------------------------
5670 
5672 {
5673  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5674  int Position1, Position2;
5675  TTrackElement TrackElement1, TrackElement2;
5676  TGapMapIterator GapMapPtr;
5677 
5678  if(!GapMap.empty())
5679  {
5680  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5681  {
5682  int HLoc1 = GapMapPtr->first.first;
5683  int VLoc1 = GapMapPtr->first.second;
5684  int HLoc2 = GapMapPtr->second.first;
5685  int VLoc2 = GapMapPtr->second.second;
5686  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5687  {
5688  throw Exception("Failed to find H & V for gap1, GapMap in error");
5689  }
5690  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5691  {
5692  throw Exception("Failed to find H & V for gap2, GapMap in error");
5693  }
5694  if(TrackElementAt(9, Position1).TrackType != GapJump)
5695  {
5696  throw Exception("Element at Pos1 not a gap, GapMap in error");
5697  }
5698  if(TrackElementAt(10, Position2).TrackType != GapJump)
5699  {
5700  throw Exception("Element at Pos2 not a gap, GapMap in error");
5701  }
5702  TrackElementAt(11, Position1).Conn[0] = Position2;
5703  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5704  TrackElementAt(13, Position2).Conn[0] = Position1;
5705  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5706  }
5707  }
5708  Utilities->CallLogPop(510);
5709  return(true);
5710 }
5711 
5712 // ---------------------------------------------------------------------------
5713 
5714 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5715 {
5716 // TIMPair MapEntry;
5717  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5718  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5719  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5720  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5721  TLocationNameMultiMapEntry LocationNameEntry;
5722 
5723  LocationNameEntry.first = TrackElement.LocationName;
5724  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5725  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5726  {
5727 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5728 // could arise when loading old railways with multiple NonStationNamedLocs
5729  bool FoundFlag = false;
5730  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5731  if(FoundFlag)
5732  {
5733  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5734  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5735  {
5736  Utilities->CallLogPop(1813);
5737  return;
5738  }
5739  }
5740  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5741  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5742  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5743  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5744  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5745  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5746  if(TrackElement.FixedNamedLocationElement)
5747  {
5748  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5749  LocationNameMultiMap.insert(LocationNameEntry);
5750  }
5751  if(TrackElement.HLoc < HLocMin)
5752  {
5753  HLocMin = TrackElement.HLoc;
5754  }
5755  if(TrackElement.HLoc > HLocMax)
5756  {
5757  HLocMax = TrackElement.HLoc;
5758  }
5759  if(TrackElement.VLoc < VLocMin)
5760  {
5761  VLocMin = TrackElement.VLoc;
5762  }
5763  if(TrackElement.VLoc > VLocMax)
5764  {
5765  VLocMax = TrackElement.VLoc;
5766  }
5767  }
5768  else
5769  {
5770 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5771 // shouldn't arise but leave in as a safeguard
5772  bool FoundFlag = false;
5773  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5774  if(FoundFlag)
5775  {
5776  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5777  {
5778  Utilities->CallLogPop(1814);
5779  return;
5780  }
5781  }
5782  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5783  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5784  {
5785  TrackMapKeyPair.first = TrackElement.HLoc;
5786  TrackMapKeyPair.second = TrackElement.VLoc;
5787  TrackMapEntry.first = TrackMapKeyPair;
5788  TrackMapEntry.second = TrackVector.size() - 1;
5789  TrackMap.insert(TrackMapEntry);
5790  if(TrackElement.FixedNamedLocationElement)
5791  {
5792  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5793  LocationNameMultiMap.insert(LocationNameEntry);
5794  }
5795  if(TrackElement.HLoc < HLocMin)
5796  {
5797  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5798  }
5799  if(TrackElement.HLoc > HLocMax)
5800  {
5801  HLocMax = TrackElement.HLoc;
5802  }
5803  if(TrackElement.VLoc < VLocMin)
5804  {
5805  VLocMin = TrackElement.VLoc;
5806  }
5807  if(TrackElement.VLoc > VLocMax)
5808  {
5809  VLocMax = TrackElement.VLoc;
5810  }
5811  }
5812  }
5813 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5814 // CheckMapAndInactiveTrack(6);//test
5815 
5816 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5817 // with the Platforms until layout fully loaded
5818  Utilities->CallLogPop(511);
5819 }
5820 
5821 // ---------------------------------------------------------------------------
5822 
5823 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5824 {
5825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5826  AnsiString(VLoc));
5827  THVPair TrackMapKeyPair;
5828 
5829  FoundFlag = false;
5830  TTrackMapIterator TrackMapPtr;
5831 
5832  TrackMapKeyPair.first = HLoc;
5833  TrackMapKeyPair.second = VLoc;
5834  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5835  if(TrackMapPtr == TrackMap.end())
5836  {
5837  Utilities->CallLogPop(512);
5838  return(-1); // nothing found
5839  }
5840  else
5841  {
5842  FoundFlag = true;
5843  Utilities->CallLogPop(513);
5844  return(TrackMapPtr->second);
5845  }
5846 }
5847 
5848 // ---------------------------------------------------------------------------
5849 
5850 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5851 {
5852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5853  AnsiString(VLoc));
5854  THVPair TrackMapKeyPair;
5855  TTrackMapIterator TrackMapPtr;
5856 
5857  TrackMapKeyPair.first = HLoc;
5858  TrackMapKeyPair.second = VLoc;
5859  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5860  if(TrackMapPtr == TrackMap.end())
5861  {
5862  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5863  throw Exception(Message);
5864  }
5865  else
5866  {
5867  Utilities->CallLogPop(1943);
5868  return(TrackElementAt(871, TrackMapPtr->second));
5869  }
5870 }
5871 
5872 // ---------------------------------------------------------------------------
5873 
5874 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5875 { //modded at v2.9.2 to make Map & Vector references
5876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5877  AnsiString(VLoc));
5878  THVPair MapKeyPair;
5879  TTrackMapIterator MapPtr;
5880 
5881  MapKeyPair.first = HLoc;
5882  MapKeyPair.second = VLoc;
5883  MapPtr = Map.find(MapKeyPair);
5884  if(MapPtr == Map.end())
5885  {
5886  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5887  throw Exception(Message);
5888  }
5889  else
5890  {
5891  Utilities->CallLogPop(2280);
5892  return(Vector.at(MapPtr->second));
5893  }
5894 }
5895 
5896 // ---------------------------------------------------------------------------
5897 
5899 {
5900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5901  AnsiString(VLoc));
5902  THVPair InactiveTrackMapKeyPair;
5903  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5904 
5905  InactiveTrackMapKeyPair.first = HLoc;
5906  InactiveTrackMapKeyPair.second = VLoc;
5907  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5908  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5909  {
5910  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5911  throw Exception(Message);
5912  }
5913  else
5914  {
5915  Utilities->CallLogPop(1949);
5916  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5917  }
5918 }
5919 
5920 // ---------------------------------------------------------------------------
5921 
5922 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5923 {
5924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5925  bool Present = true;
5926  THVPair TrackMapKeyPair;
5927  TTrackMapIterator TrackMapPtr;
5928 
5929  TrackMapKeyPair.first = HLoc;
5930  TrackMapKeyPair.second = VLoc;
5931  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5932  if(TrackMapPtr == TrackMap.end())
5933  {
5934  Present = false;
5935  }
5936  Utilities->CallLogPop(2057);
5937  return(Present);
5938 }
5939 
5940 // ---------------------------------------------------------------------------
5941 
5942 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5943 {
5944  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5945  AnsiString(VLoc));
5946  bool Present = true;
5947  THVPair InactiveTrackMapKeyPair;
5948  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5949 
5950  InactiveTrackMapKeyPair.first = HLoc;
5951  InactiveTrackMapKeyPair.second = VLoc;
5952  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5953  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5954  {
5955  Present = false;
5956  }
5957  Utilities->CallLogPop(2058);
5958  return(Present);
5959 }
5960 
5961 // ---------------------------------------------------------------------------
5962 
5963 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5964 // max number of elements is 2, for platforms
5965 // note that both elements of RetPair may be the same, if only one present in map
5966 {
5967  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5968  AnsiString(VLoc));
5969  THVPair InactiveTrackMapKeyPair;
5970  TIMPair RetPair;
5971  TInactiveTrackRange InactiveTrackRange;
5972 
5973  FoundFlag = false;
5974  InactiveTrackMapKeyPair.first = HLoc;
5975  InactiveTrackMapKeyPair.second = VLoc;
5976  if(InactiveTrack2MultiMap.empty())
5977  {
5978  RetPair.first = 0;
5979  RetPair.second = 0;
5980  Utilities->CallLogPop(1815);
5981  return(RetPair); // map empty
5982  }
5983  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5984  if(InactiveTrackRange.first == InactiveTrackRange.second)
5985  {
5986  RetPair.first = 0;
5987  RetPair.second = 0;
5988  Utilities->CallLogPop(514);
5989  return(RetPair); // nothing found
5990  }
5991  else
5992  {
5993  RetPair.first = InactiveTrackRange.first->second;
5994  RetPair.second = (--InactiveTrackRange.second)->second;
5995  FoundFlag = true;
5996  Utilities->CallLogPop(515);
5997  return(RetPair);
5998  }
5999 }
6000 
6001 // ---------------------------------------------------------------------------
6002 
6003 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6004 {
6005 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6007  AnsiString(DivergingPosition));
6008  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6009  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6010  int SpeedTag1 = T1.SpeedTag;
6011  int SpeedTag2 = T2.SpeedTag;
6012 
6013  if((T1.Attribute) != (T2.Attribute))
6014  {
6015  Utilities->CallLogPop(516);
6016  return(false);
6017  }
6018  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6019  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6020  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6021  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6022  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6023  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6024  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6025  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6026  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6027  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6028  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6029  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6030  {
6031  Utilities->CallLogPop(517);
6032  return(true);
6033  }
6034  else
6035  {
6036  Utilities->CallLogPop(518);
6037  return(false);
6038  }
6039 }
6040 
6041 // ---------------------------------------------------------------------------
6042 
6043 /*
6044  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6045  {
6046  if(lower.second < higher.second) return true;
6047  else if(lower.second > higher.second) return false;
6048  else if(lower.second == higher.second)
6049  {
6050  if(lower.first < higher.first) return true;
6051  }
6052  return false;
6053  }
6054 */
6055 // ---------------------------------------------------------------------------
6056 
6057 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6058 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6059 {
6060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6061  if(TrackElement.TrackType != GapJump)
6062  {
6063  throw Exception("Error, Wrong track type in PlotGap");
6064  }
6065  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6066  {
6067  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6068  }
6069  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6070  {
6071  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6072  }
6073  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6074  {
6075  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6076  }
6077  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6078  {
6079  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6080  }
6081  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6082  {
6083  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6084  }
6085  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6086  {
6087  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6088  }
6089  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6090  {
6091  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6092  }
6093  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6094  {
6095  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6096  }
6097  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6098  {
6099  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6100  }
6101  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6102  {
6103  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6104  }
6105  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6106  {
6107  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6108  }
6109  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6110  {
6111  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6112  }
6113  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6114  {
6115  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6116  }
6117  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6118  {
6119  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6120  }
6121  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6122  {
6123  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6124  }
6125  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6126  {
6127  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6128  }
6129  Utilities->CallLogPop(1101);
6130 }
6131 
6132 // ---------------------------------------------------------------------------
6133 
6134 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6135 {
6136  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6137  TrackElement.PlotVariableTrackElement(7, Disp);
6138  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6139  {
6140  THVPair PosPair;
6141  PosPair.first = TrackElement.HLoc;
6142  PosPair.second = TrackElement.VLoc;
6143  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6144  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6145  {
6146  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6147  }
6148  }
6149  Utilities->CallLogPop(2403);
6150 }
6151 
6152 // ---------------------------------------------------------------------------
6153 
6154 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6155 {
6156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6157  if(TrackElement.TrackType != Points)
6158  {
6159  throw Exception("Error, Wrong track type in PlotPoints");
6160  }
6161  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6162  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6163  bool FoundFlag = false;
6164  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6165  if(IMPair.first > 0) //can only have one entry in IMPair for points
6166  {
6167  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6168  if(ITE.SpeedTag == 131)
6169  {
6170  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6171  }
6172  }
6173  TrackElement.PlotVariableTrackElement(4, Disp);
6174  if(BothFillets)
6175  {
6176  if(TrackElement.SpeedTag < 28)
6177  {
6178  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6179  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6180  }
6181  else if(TrackElement.SpeedTag < 132)
6182  {
6183  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6184  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6185  }
6186  else
6187  {
6188  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6189  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6190  }
6191  }
6192  else if(!TrackElement.Failed) //not failed
6193  {
6194  if(TrackElement.SpeedTag < 28)
6195  {
6196  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6197  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6198  }
6199  else if(TrackElement.SpeedTag < 132)
6200  {
6201  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6202  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6203  }
6204  else
6205  {
6206  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6207  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6208  }
6209  }
6210  else //failed in fixed position
6211  {
6212  if(TrackElement.SpeedTag < 28)
6213  {
6214  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6215  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6216  }
6217  else if(TrackElement.SpeedTag < 132)
6218  {
6219  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6220  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6221  }
6222  else
6223  {
6224  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6225  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6226  }
6227  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6228  }
6229 // replot platform if required
6230  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6231  bool BlueLoc = false;
6232  if(FoundFlag)
6233  {
6234  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6235  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these or the track is obscured - added at v2.18.0
6236  {
6237  BlueLoc = true;
6238  }
6239  }
6240  if(FoundFlag && !BlueLoc)
6241  {
6242  // only one platform possible at points so only need to plot IMPair.first
6243  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6244  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6245  }
6246  Utilities->CallLogPop(519);
6247 }
6248 
6249 // ---------------------------------------------------------------------------
6250 
6251 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6252 {
6253 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6255  bool FoundFlag = false;
6256  if(TrackElement.TrackType != SignalPost)
6257  {
6258  throw Exception("Error, Wrong track type in PlotSignal");
6259  }
6260  if(!TrackElement.Failed) //added at v2.13.0
6261  {
6262  for(int x = 0; x < 40; x++)
6263  {
6264  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6265  {
6266  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6267  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6268  // in case existing signal is a double yellow
6269  // plot platforms if present
6270  // Graphics::TBitmap* SignalPlatformGraphic;
6271  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6272  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6273  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6274  // to not be plotted with the above function.
6275 
6276  //replot the blue square to cover the blank area - added at v2.18.0
6277  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(36, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6278  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6279  {
6280  TTrackElement ITE = InactiveTrackElementAt(1414, IMPair.first);
6281  if(ITE.SpeedTag == 131)
6282  {
6283  ITE.PlotVariableTrackElement(9, Disp); //plot the blue square again to cover the blank area
6284  }
6285  }
6286 
6287  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6288  // now plot signal (double yellow overwrites most of signal platform if present)
6289  // additions at version 0.6 for other aspects & ground sigs
6290  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6291  {
6292  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6293  }
6294  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6295  {
6296  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6297  }
6298  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6299  {
6300  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6301  }
6302  else // 4 aspect
6303  {
6304  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6305  }
6306  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6307  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6308  {
6309  if(TrackElement.SpeedTag == 68)
6310  {
6311  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6312  }
6313  if(TrackElement.SpeedTag == 69)
6314  {
6315  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6316  }
6317  if(TrackElement.SpeedTag == 70)
6318  {
6319  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6320  }
6321  if(TrackElement.SpeedTag == 71)
6322  {
6323  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6324  }
6325  if(TrackElement.SpeedTag == 72)
6326  {
6327  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6328  }
6329  if(TrackElement.SpeedTag == 73)
6330  {
6331  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6332  }
6333  if(TrackElement.SpeedTag == 74)
6334  {
6335  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6336  }
6337  if(TrackElement.SpeedTag == 75)
6338  {
6339  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6340  }
6341  }
6342  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6343  // ground signal calling on, need to use normal proceed aspect
6344  {
6345  for(int x = 0; x < 40; x++)
6346  {
6347  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6348  {
6349  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6350  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6351  // plot special signal platform if present
6352  Graphics::TBitmap* SignalPlatformGraphic;
6353  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(37, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6354  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6355  {
6356  TTrackElement ITE = InactiveTrackElementAt(1415, IMPair.first);
6357  if(ITE.SpeedTag == 131)
6358  {
6359  ITE.PlotVariableTrackElement(10, Disp); //plot the blue square again to cover the blank area
6360  }
6361  }
6362  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6363  // now plot signal
6364  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6365  }
6366  }
6367  }
6368  break;
6369  }
6370  }
6371  }
6372  else //failed added at v2.13.0
6373  {
6374  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6375  {
6376  for(int x = 0; x < 8; x++)
6377  {
6378  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6379  {
6380  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6381  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6382  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(38, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6383  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6384  {
6385  TTrackElement ITE = InactiveTrackElementAt(1416, IMPair.first);
6386  if(ITE.SpeedTag == 131)
6387  {
6388  ITE.PlotVariableTrackElement(11, Disp); //plot the blue square again to cover the blank area
6389  }
6390  }
6391  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6392  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6393  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6394  break;
6395  }
6396  }
6397  }
6398  else
6399  {
6400  for(int x = 0; x < 8; x++)
6401  {
6402  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6403  {
6404  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6405  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6406  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(39, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6407  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6408  {
6409  TTrackElement ITE = InactiveTrackElementAt(1417, IMPair.first);
6410  if(ITE.SpeedTag == 131)
6411  {
6412  ITE.PlotVariableTrackElement(12, Disp); //plot the blue square again to cover the blank area
6413  }
6414  }
6415  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6416  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6417  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6418  break;
6419  }
6420  }
6421  }
6422  }
6423  Utilities->CallLogPop(520);
6424 }
6425 
6426 // ---------------------------------------------------------------------------
6427 
6428 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6429 {
6430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6431  bool FoundFlag;
6432  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6433 
6434  if(!FoundFlag)
6435  {
6436  Utilities->CallLogPop(2112);
6437  return;
6438  }
6439  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6440  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6441 
6442  // don't want 'else if' for the below as may need to plot 2 platforms
6443  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6444  {
6445  if(IAElement1.LocationName == "") // '2' will be same
6446  {
6447  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6448  }
6449  else
6450  {
6451  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6452  }
6453  }
6454  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6455  {
6456  if(IAElement1.LocationName == "") // '2' will be same
6457  {
6458  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6459  }
6460  else
6461  {
6462  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6463  }
6464  }
6465  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6466  {
6467  if(IAElement1.LocationName == "") // '2' will be same
6468  {
6469  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6470  }
6471  else
6472  {
6473  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6474  }
6475  }
6476  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6477  {
6478  if(IAElement1.LocationName == "") // '2' will be same
6479  {
6480  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6481  }
6482  else
6483  {
6484  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6485  }
6486  }
6487  Utilities->CallLogPop(2113);
6488 }
6489 
6490 // ---------------------------------------------------------------------------
6491 
6492 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6493 {
6494 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6495  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6496  AnsiString(VLoc));
6497 // find topmost LC, opening them all (to trains) in turn
6498  int UpStep = 0;
6499 
6500  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6501  {
6502  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6503  UpStep--;
6504  }
6505 // now find bottommost LC, opening them all (to trains) in turn
6506  int DownStep = 1;
6507 
6508  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6509  {
6510  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6511  DownStep++;
6512  }
6513 // find leftmost LC, opening them all (to trains) in turn
6514  int LeftStep = 0;
6515 
6516  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6517  {
6518  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6519  LeftStep--;
6520  }
6521 // now find rightmost LC, opening them all (to trains) in turn
6522  int RightStep = 1;
6523 
6524  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6525  {
6526  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6527  RightStep++;
6528  }
6529  Utilities->CallLogPop(1915);
6530 }
6531 
6532 // ---------------------------------------------------------------------------
6533 
6534 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6535 {
6536  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6537 // work upwards setting all to manual
6538  int UpStep = -1;
6539 
6540  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6541  {
6542  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6543  UpStep--;
6544  }
6545 // work downwards setting all to manual
6546  int DownStep = 1;
6547 
6548  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6549  {
6550  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6551  DownStep++;
6552  }
6553 // work leftwards setting all to manual
6554  int LeftStep = -1;
6555 
6556  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6557  {
6558  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6559  LeftStep--;
6560  }
6561 // work rightwards setting all to manual
6562  int RightStep = 1;
6563 
6564  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6565  {
6566  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6567  RightStep++;
6568  }
6569  Utilities->CallLogPop(2242);
6570 }
6571 
6572 // ---------------------------------------------------------------------------
6573 
6574 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6575 {
6576  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6578  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6579  {
6580  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6581  {
6582  BarriersDownVector.at(x).TypeOfRoute = 2;
6583  break;
6584  }
6585  }
6586  Utilities->CallLogPop(2243);
6587 }
6588 
6589 // ---------------------------------------------------------------------------
6590 
6591 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6592 {
6593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6594 // work upwards
6595  int UpStep = 0; //start with this location
6596 
6597  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6598  {
6599  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6600  {
6601  Utilities->CallLogPop(2244);
6602  return(true);
6603  }
6604  UpStep--;
6605  }
6606 // work downwards
6607  int DownStep = 1;
6608 
6609  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6610  {
6611  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6612  {
6613  Utilities->CallLogPop(2245);
6614  return(true);
6615  }
6616  DownStep++;
6617  }
6618 // work leftwards
6619  int LeftStep = -1;
6620 
6621  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6622  {
6623  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6624  {
6625  Utilities->CallLogPop(2246);
6626  return(true);
6627  }
6628  LeftStep--;
6629  }
6630 // work rightwards
6631  int RightStep = 1;
6632 
6633  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6634  {
6635  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6636  {
6637  Utilities->CallLogPop(2247);
6638  return(true);
6639  }
6640  RightStep++;
6641  }
6642  Utilities->CallLogPop(2248);
6643  return(false);
6644 }
6645 
6646 // ---------------------------------------------------------------------------
6647 
6648 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6649 {
6650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6651  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6652  {
6653  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6654  {
6655  BDVectorPos = x;
6656  Utilities->CallLogPop(2249);
6657  return(true);
6658  }
6659  }
6660  BDVectorPos = -1;
6661  Utilities->CallLogPop(2250);
6662  return(false);
6663 }
6664 
6665 // ---------------------------------------------------------------------------
6666 
6667 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6668 // open to trains
6669 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6670 {
6671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6672  AnsiString(VLoc));
6673  if(!IsLCAtHV(4, HLoc, VLoc))
6674  {
6675  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6676  }
6677  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6678  {
6679  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6680  }
6681 // check for adjacent LCs & if so open (to trains)
6682  if(BaseElementSpeedTag == 1) // hor track element
6683  {
6684  // find topmost LC, opening them all (to trains) in turn
6685  int UpStep = 0;
6686  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6687  {
6688  UpStep--;
6689  }
6690  UpStep++;
6691  // now find bottommost LC, opening them all (to trains) in turn
6692  int DownStep = 1;
6693  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6694  {
6695  DownStep++;
6696  }
6697  DownStep--;
6698  // now plot graphics, UpStep is smallest & DownStep largest
6699  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6700  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6701  Graphics::TBitmap *RouteGraphic;
6702  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6703  if(TypeOfRoute == 1)
6704  {
6705  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6706  }
6707  else if(TypeOfRoute == 0)
6708  {
6709  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6710  }
6711  else //manual - no route
6712  {
6713  RouteGraphic = BaseGraphic;
6714  }
6715 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6716 // LinkSigRouteGraphicsPtr[1] ver }
6717 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6718 // LinkNonSigRouteGraphicsPtr[1] ver }
6719 
6720  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6721  {
6722  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6723  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6724  if(!Manual)
6725  {
6726  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6727  }
6728  else
6729  {
6730  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6731  }
6732  }
6733  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6734  {
6735  if(UpStep == 0)
6736  {
6737  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6738  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6739  if(!Manual)
6740  {
6741  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6742  }
6743  else
6744  {
6745  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6746  }
6747  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6748  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6749  if(!Manual)
6750  {
6751  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6752  }
6753  else
6754  {
6755  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6756  }
6757  }
6758  else
6759  {
6760  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6761  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6762  if(!Manual)
6763  {
6764  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6765  }
6766  else
6767  {
6768  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6769  }
6770  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6771  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6772  if(!Manual)
6773  {
6774  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6775  }
6776  else
6777  {
6778  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6779  }
6780  }
6781  }
6782  else // at least one plain graphic
6783  {
6784  if(UpStep == 0)
6785  {
6786  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6787  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6788  if(!Manual)
6789  {
6790  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6791  }
6792  else
6793  {
6794  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6795  }
6796  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6797  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6798  if(!Manual)
6799  {
6800  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6801  }
6802  else
6803  {
6804  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6805  }
6806  }
6807  else if(DownStep == 0)
6808  {
6809  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6810  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6811  if(!Manual)
6812  {
6813  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6814  }
6815  else
6816  {
6817  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6818  }
6819  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6820  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6821  if(!Manual)
6822  {
6823  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6824  }
6825  else
6826  {
6827  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6828  }
6829  }
6830  else
6831  {
6832  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6833  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6834  if(!Manual)
6835  {
6836  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6837  }
6838  else
6839  {
6840  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6841  }
6842  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6843  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6844  if(!Manual)
6845  {
6846  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6847  }
6848  else
6849  {
6850  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6851  }
6852  }
6853  for(int x = (UpStep + 1); x < DownStep; x++)
6854  {
6855  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6856  if(x == 0)
6857  {
6858  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6859  }
6860  else
6861  {
6862  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6863  }
6864  if(!Manual)
6865  {
6866  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6867  }
6868  else
6869  {
6870  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6871  }
6872  }
6873  }
6874  Disp->Update();
6875  Utilities->CallLogPop(1958);
6876  return;
6877  }
6878 
6879  else // ver track element
6880  {
6881  // find leftmost LC, opening them all (to trains) in turn
6882  int LStep = 0;
6883  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6884  {
6885  LStep--;
6886  }
6887  LStep++;
6888  // now find rightmost LC, opening them all (to trains) in turn
6889  int RStep = 1;
6890  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6891  {
6892  RStep++;
6893  }
6894  RStep--;
6895  // now plot graphics, LStep is smallest & RStep largest
6896  Graphics::TBitmap *RouteGraphic;
6897  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6898  if(TypeOfRoute == 1)
6899  {
6900  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6901  }
6902  else if(TypeOfRoute == 0)
6903  {
6904  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6905  }
6906  else //manual
6907  {
6908  RouteGraphic = BaseGraphic;
6909  }
6910 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6911 // LinkSigRouteGraphicsPtr[1] ver }
6912 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6913 // LinkNonSigRouteGraphicsPtr[1] ver }
6914  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6915  {
6916  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6917  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6918  if(!Manual)
6919  {
6920  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6921  }
6922  else
6923  {
6924  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6925  }
6926  }
6927  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6928  {
6929  if(LStep == 0)
6930  {
6931  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6932  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6933  if(!Manual)
6934  {
6935  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6936  }
6937  else
6938  {
6939  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6940  }
6941  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6942  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6943  if(!Manual)
6944  {
6945  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6946  }
6947  else
6948  {
6949  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6950  }
6951  }
6952  else
6953  {
6954  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6955  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6956  if(!Manual)
6957  {
6958  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6959  }
6960  else
6961  {
6962  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6963  }
6964  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6965  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6966  if(!Manual)
6967  {
6968  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6969  }
6970  else
6971  {
6972  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6973  }
6974  }
6975  }
6976  else // at least one plain graphic
6977  {
6978  if(LStep == 0)
6979  {
6980  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6981  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6982  if(!Manual)
6983  {
6984  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6985  }
6986  else
6987  {
6988  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6989  }
6990  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6991  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6992  if(!Manual)
6993  {
6994  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6995  }
6996  else
6997  {
6998  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6999  }
7000  }
7001  else if(RStep == 0)
7002  {
7003  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7004  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7005  if(!Manual)
7006  {
7007  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7008  }
7009  else
7010  {
7011  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7012  }
7013  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7014  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7015  if(!Manual)
7016  {
7017  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7018  }
7019  else
7020  {
7021  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7022  }
7023  }
7024  else
7025  {
7026  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7027  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7028  if(!Manual)
7029  {
7030  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7031  }
7032  else
7033  {
7034  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7035  }
7036  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7037  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7038  if(!Manual)
7039  {
7040  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7041  }
7042  else
7043  {
7044  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7045  }
7046  }
7047  for(int x = (LStep + 1); x < RStep; x++)
7048  {
7049  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7050  if(x == 0)
7051  {
7052  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7053  }
7054  else
7055  {
7056  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7057  }
7058  if(!Manual)
7059  {
7060  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7061  }
7062  else
7063  {
7064  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7065  }
7066  }
7067  }
7068  Disp->Update();
7069  Utilities->CallLogPop(1896);
7070  return;
7071  }
7072 }
7073 
7074 // ---------------------------------------------------------------------------
7075 
7076 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7077 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7078 {
7079  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7080  AnsiString(HLoc) + "," + AnsiString(VLoc));
7081  if(!IsLCAtHV(29, HLoc, VLoc))
7082  {
7083  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7084  }
7085  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7086  {
7087  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7088  }
7089 // check for adjacent LCs & if so open (to trains)
7090  if(BaseElementSpeedTag == 1) // hor track element
7091  {
7092  // find topmost LC, opening them all (to trains) in turn
7093  int UpStep = 0;
7094  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7095  {
7096  UpStep--;
7097  }
7098  UpStep++;
7099  // now find bottommost LC, opening them all (to trains) in turn
7100  int DownStep = 1;
7101  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7102  {
7103  DownStep++;
7104  }
7105  DownStep--;
7106  // now plot graphics, UpStep is smallest & DownStep largest
7107  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7108  {
7109  if(!Manual)
7110  {
7111  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7112  }
7113  else
7114  {
7115  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7116  }
7117  }
7118  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7119  {
7120  if(!Manual)
7121  {
7122  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7123  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7124  }
7125  else
7126  {
7127  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7128  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7129  }
7130  }
7131  else // at least one plain graphic
7132  {
7133  if(!Manual)
7134  {
7135  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7136  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7137  for(int x = (UpStep + 1); x < DownStep; x++)
7138  {
7139  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7140  }
7141  }
7142  else
7143  {
7144  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7145  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7146  for(int x = (UpStep + 1); x < DownStep; x++)
7147  {
7148  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7149  }
7150  }
7151  }
7152  // set markers
7153  for(int x = UpStep; x <= DownStep; x++)
7154  {
7155  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7156  }
7157  Display->Update();
7158  Utilities->CallLogPop(1944);
7159  return;
7160  }
7161 
7162  else // ver track element
7163  {
7164  // find leftmost LC, opening them all (to trains) in turn
7165  int LStep = 0;
7166  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7167  {
7168  LStep--;
7169  }
7170  LStep++;
7171  // now find rightmost LC, opening them all (to trains) in turn
7172  int RStep = 1;
7173  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7174  {
7175  RStep++;
7176  }
7177  RStep--;
7178  // now plot graphics, LStep is smallest & RStep largest
7179  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7180  {
7181  if(!Manual)
7182  {
7183  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7184  }
7185  else
7186  {
7187  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7188  }
7189  }
7190  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7191  {
7192  if(!Manual)
7193  {
7194  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7195  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7196  }
7197  else
7198  {
7199  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7200  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7201  }
7202  }
7203  else // at least one plain graphic
7204  {
7205  if(!Manual)
7206  {
7207  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7208  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7209  for(int x = (LStep + 1); x < RStep; x++)
7210  {
7211  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7212  }
7213  }
7214  else
7215  {
7216  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7217  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7218  for(int x = (LStep + 1); x < RStep; x++)
7219  {
7220  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7221  }
7222  }
7223  }
7224  // set markers
7225  for(int x = LStep; x <= RStep; x++)
7226  {
7227  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7228  }
7229  Disp->Update();
7230  Utilities->CallLogPop(1945);
7231  return;
7232  }
7233 }
7234 
7235 // ---------------------------------------------------------------------------
7236 
7237 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7238 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7239 {
7240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7241  AnsiString(VLoc));
7242  if(!IsLCAtHV(9, HLoc, VLoc))
7243  {
7244  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7245  }
7246  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7247  {
7248  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7249  }
7250 // check for adjacent LCs & if so close (to trains)
7251  if(BaseElementSpeedTag == 1) // hor track element
7252  {
7253  // find topmost LC, closing them all (to trains) in turn
7254  int UpStep = 0;
7255  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7256  {
7257  UpStep--;
7258  }
7259  UpStep++;
7260  // now find bottommost LC, opening them all (to trains) in turn
7261  int DownStep = 1;
7262  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7263  {
7264  DownStep++;
7265  }
7266  DownStep--;
7267  // now plot graphics, UpStep is smallest & DownStep largest
7268  for(int x = UpStep; x < (DownStep + 1); x++)
7269  {
7270  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7271  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7272  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7273  }
7274  Disp->Update();
7275  Utilities->CallLogPop(1959);
7276  return;
7277  }
7278 
7279  else // ver track element
7280  {
7281  // find leftmost LC, closing them all (to trains) in turn
7282  int LStep = 0;
7283  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7284  {
7285  LStep--;
7286  }
7287  LStep++;
7288  // now find rightmost LC, opening them all (to trains) in turn
7289  int RStep = 1;
7290  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7291  {
7292  RStep++;
7293  }
7294  RStep--;
7295  // now plot graphics, LStep is smallest & RStep largest
7296  for(int x = LStep; x < (RStep + 1); x++)
7297  {
7298  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7299  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7300  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7301  }
7302  Disp->Update();
7303  Utilities->CallLogPop(1960);
7304  return;
7305  }
7306 }
7307 
7308 // ---------------------------------------------------------------------------
7309 
7310 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7311 // closed to trains
7312 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7313 {
7314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7315  AnsiString(HLoc) + "," + AnsiString(VLoc));
7316  if(!IsLCAtHV(34, HLoc, VLoc))
7317  {
7318  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7319  }
7320  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7321  {
7322  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7323  }
7324  TTrackElement TE;
7325 
7326 // check for adjacent LCs & if so close (to trains)
7327  if(BaseElementSpeedTag == 1) // hor track element
7328  {
7329  // find topmost LC, closing them all (to trains) in turn
7330  int UpStep = 0;
7331  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7332  {
7333  UpStep--;
7334  }
7335  UpStep++;
7336  // now find bottommost LC, opening them all (to trains) in turn
7337  int DownStep = 1;
7338  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7339  {
7340  DownStep++;
7341  }
7342  DownStep--;
7343  // now plot graphics, UpStep is smallest & DownStep largest
7344  for(int x = UpStep; x <= DownStep; x++)
7345  {
7346  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7347  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7348  }
7349  Display->Update();
7350  Utilities->CallLogPop(1946);
7351  return;
7352  }
7353 
7354  else // ver track element
7355  {
7356  // find leftmost LC, closing them all (to trains) in turn
7357  int LStep = 0;
7358  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7359  {
7360  LStep--;
7361  }
7362  LStep++;
7363  // now find rightmost LC, opening them all (to trains) in turn
7364  int RStep = 1;
7365  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7366  {
7367  RStep++;
7368  }
7369  RStep--;
7370  // now plot graphics, LStep is smallest & RStep largest
7371  for(int x = LStep; x <= RStep; x++)
7372  {
7373  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7374  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7375  }
7376  Display->Update();
7377  Utilities->CallLogPop(1947);
7378  return;
7379  }
7380 }
7381 
7382 // ---------------------------------------------------------------------------
7383 
7384 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7385 {
7386  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7387  Graphics::TBitmap *RouteGraphic;
7388  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7389 
7390  if(BaseElementSpeedTag == 1)
7391  {
7392  if(TypeOfRoute == 1)
7393  {
7394  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7395  }
7396  else if(TypeOfRoute == 0)
7397  {
7398  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7399  }
7400  else //manual
7401  {
7402  RouteGraphic = BaseGraphic;
7403  }
7404  if(State == Raising)
7405  {
7406  RouteGraphic = BaseGraphic;
7407  }
7408  }
7409  else
7410  {
7411  BaseGraphic = RailGraphics->gl2;
7412  if(TypeOfRoute == 1)
7413  {
7414  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7415  }
7416  else if(TypeOfRoute == 0)
7417  {
7418  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7419  }
7420  else
7421  {
7422  RouteGraphic = BaseGraphic; //manual
7423  }
7424  if(State == Raising)
7425  {
7426  RouteGraphic = BaseGraphic;
7427  }
7428  }
7429  int UpStep = 0;
7430 
7431  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7432  {
7433  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7434  if(UpStep == 0)
7435  {
7436  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7437  }
7438  else
7439  {
7440  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7441  }
7442  UpStep--;
7443  }
7444 // now find bottommost LC, opening them all (to trains) in turn
7445  int DownStep = 1;
7446 
7447  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7448  {
7449  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7450  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7451  DownStep++;
7452  }
7453  int LeftStep = 0;
7454 
7455  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7456  {
7457  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7458  if(LeftStep == 0)
7459  {
7460  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7461  }
7462  else
7463  {
7464  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7465  }
7466  LeftStep--;
7467  }
7468 // now find rightmost LC, opening them all (to trains) in turn
7469  int RightStep = 1;
7470 
7471  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7472  {
7473  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7474  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7475  RightStep++;
7476  }
7477  Disp->Update();
7478  Utilities->CallLogPop(1914);
7479 }
7480 
7481 // ---------------------------------------------------------------------------
7482 
7483 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7484 {
7485 // return false for no LC there, flashing or a closed (to trains) LC
7486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7487  bool FoundFlag;
7488  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7489 
7490  if(!FoundFlag)
7491  {
7492  Utilities->CallLogPop(1898);
7493  return(false);
7494  }
7495  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7496  {
7497  Utilities->CallLogPop(1899);
7498  return(false);
7499  }
7500  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7501  {
7502  Utilities->CallLogPop(1900);
7503  return(true);
7504  }
7505  Utilities->CallLogPop(1901);
7506  return(false);
7507 }
7508 
7509 // ---------------------------------------------------------------------------
7510 
7511 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7512 {
7513 // return false for no LC there, flashing LC or open (to trains) LC
7514  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7515  bool FoundFlag;
7516  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7517 
7518  if(!FoundFlag)
7519  {
7520  Utilities->CallLogPop(1922);
7521  return(false);
7522  }
7523  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7524  {
7525  Utilities->CallLogPop(1923);
7526  return(false);
7527  }
7528  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7529  {
7530  Utilities->CallLogPop(1924);
7531  return(true);
7532  }
7533  Utilities->CallLogPop(1925);
7534  return(false);
7535 }
7536 
7537 // ---------------------------------------------------------------------------
7538 
7539 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7540 {
7541 // return true for barrier in process of moving
7542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7543  bool FoundFlag;
7544  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7545 
7546  if(!FoundFlag)
7547  {
7548  Utilities->CallLogPop(1918);
7549  return(false);
7550  }
7551  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7552  {
7553  Utilities->CallLogPop(1919);
7554  return(false);
7555  }
7556  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7557  {
7558  Utilities->CallLogPop(1920);
7559  return(true);
7560  }
7561  Utilities->CallLogPop(1921);
7562  return(false);
7563 }
7564 
7565 // ---------------------------------------------------------------------------
7566 
7567 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7568 {
7569 // return true for an LC at H&V
7570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7571  bool FoundFlag;
7572  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7573 
7574  if(!FoundFlag)
7575  {
7576  Utilities->CallLogPop(1902);
7577  return(false);
7578  }
7579  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7580  {
7581  Utilities->CallLogPop(1903);
7582  return(false);
7583  }
7584  Utilities->CallLogPop(1904);
7585  return(true);
7586 }
7587 
7588 // ---------------------------------------------------------------------------
7589 
7590 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7591 {
7592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7593  AnsiString(Attr));
7594  bool FoundFlag;
7595  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7596 
7597  if(!FoundFlag)
7598  {
7599  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7600  }
7601  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7602  {
7603  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7604  }
7605  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7606  Utilities->CallLogPop(1905);
7607  return;
7608 }
7609 
7610 // ---------------------------------------------------------------------------
7611 
7613 {
7614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7615  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7616  {
7617  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7618  if(InactiveTrackElement.TrackType == LevelCrossing)
7619  {
7620  InactiveTrackElementAt(141, x).Attribute = 0;
7621  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7622  }
7623  }
7624  Utilities->CallLogPop(1913);
7625  return;
7626 }
7627 
7628 // ---------------------------------------------------------------------------
7629 
7630 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7631 {
7632 // return true if there is either a route set or being set on any element or a train on any element
7633  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7634  "," + AnsiString(VLoc));
7635 
7636  THVPair TrackMapKeyPair;
7637  TTrack::TTrackMapIterator TrackMapPtr;
7638  int DummyRouteNumber;
7639 
7640  TrainPresent = false;
7641 // find topmost LC, checking each for routes & trains
7642  int UpStep = 0;
7643 
7644  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7645  {
7646  TrackMapKeyPair.first = HLoc;
7647  TrackMapKeyPair.second = VLoc + UpStep;
7648  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7649  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7650  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7651  {
7652  Utilities->CallLogPop(1932);
7653  return(true);
7654  }
7655  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7656  {
7657  TrainPresent = true;
7658  Utilities->CallLogPop(1933);
7659  return(true);
7660  }
7661  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7662  {
7663  Utilities->CallLogPop(2274);
7664  return(true);
7665  }
7666  UpStep--;
7667  }
7668 // now find bottommost LC, opening them all (to trains) in turn
7669  int DownStep = 1;
7670 
7671  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7672  {
7673  TrackMapKeyPair.first = HLoc;
7674  TrackMapKeyPair.second = VLoc + DownStep;
7675  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7676  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7677  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7678  {
7679  Utilities->CallLogPop(1934);
7680  return(true);
7681  }
7682  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7683  {
7684  TrainPresent = true;
7685  Utilities->CallLogPop(1935);
7686  return(true);
7687  }
7688  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7689  {
7690  Utilities->CallLogPop(2275);
7691  return(true);
7692  }
7693  DownStep++;
7694  }
7695 // find leftmost LC
7696  int LeftStep = 0;
7697 
7698  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7699  {
7700  TrackMapKeyPair.first = HLoc + LeftStep;
7701  TrackMapKeyPair.second = VLoc;
7702  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7703  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7704  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7705  {
7706  Utilities->CallLogPop(1936);
7707  return(true);
7708  }
7709  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7710  {
7711  TrainPresent = true;
7712  Utilities->CallLogPop(1937);
7713  return(true);
7714  }
7715  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7716  {
7717  Utilities->CallLogPop(2276);
7718  return(true);
7719  }
7720  LeftStep--;
7721  }
7722 // now find rightmost LC, opening them all (to trains) in turn
7723  int RightStep = 1;
7724 
7725  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7726  {
7727  TrackMapKeyPair.first = HLoc + RightStep;
7728  TrackMapKeyPair.second = VLoc;
7729  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7730  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7731  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7732  {
7733  Utilities->CallLogPop(1938);
7734  return(true);
7735  }
7736  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7737  {
7738  TrainPresent = true;
7739  Utilities->CallLogPop(1939);
7740  return(true);
7741  }
7742  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7743  {
7744  Utilities->CallLogPop(2277);
7745  return(true);
7746  }
7747  RightStep++;
7748  }
7749  Utilities->CallLogPop(1940);
7750  return(false);
7751 }
7752 
7753 // ---------------------------------------------------------------------------
7754 
7755 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7756 {
7757  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7758  for(unsigned int x = 0; x < SearchVector.size(); x++)
7759  {
7760  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7761  {
7762  Utilities->CallLogPop(2278);
7763  return(true);
7764  }
7765  }
7766  Utilities->CallLogPop(2279);
7767  return(false);
7768 }
7769 
7770 // ---------------------------------------------------------------------------
7771 
7772 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7773 {
7774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7775  AnsiString(HLoc) + "," + AnsiString(VLoc));
7776  if(!IsLCAtHV(60, HLoc, VLoc))
7777  {
7778  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7779  }
7780 
7781 // check for adjacent LCs
7782  // find topmost LC
7783  int UpStep = 0;
7784  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7785  {
7786  UpStep--;
7787  }
7788  UpStep++;
7789  // now find bottommost LC, opening them all (to trains) in turn
7790  int DownStep = 1;
7791  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7792  {
7793  DownStep++;
7794  }
7795  DownStep--;
7796  // now plot graphics, UpStep is smallest & DownStep largest
7797  for(int x = UpStep; x <= DownStep; x++)
7798  {
7799  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7800  }
7801 
7802  // find leftmost LC, closing them all (to trains) in turn
7803  int LStep = 0;
7804  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7805  {
7806  LStep--;
7807  }
7808  LStep++;
7809  // now find rightmost LC, opening them all (to trains) in turn
7810  int RStep = 1;
7811  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7812  {
7813  RStep++;
7814  }
7815  RStep--;
7816  // now plot graphics, LStep is smallest & RStep largest
7817  for(int x = LStep; x <= RStep; x++)
7818  {
7819  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7820  }
7821  Display->Update();
7822  Utilities->CallLogPop(2315);
7823  return;
7824 }
7825 
7826 // ---------------------------------------------------------------------------
7827 
7828 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7829 {
7830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7831  if(TrackElement.TrackType != Points)
7832  {
7833  throw Exception("Error, Wrong track type in GetFilletGraphic");
7834  }
7835  if(TrackElement.SpeedTag < 28)
7836  {
7837  Utilities->CallLogPop(521);
7838  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7839  }
7840  else if(TrackElement.SpeedTag < 132)
7841  {
7842  Utilities->CallLogPop(522);
7843 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7844  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7845  }
7846  else
7847  {
7848  Utilities->CallLogPop(1537);
7849  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7850  }
7851 }
7852 
7853 // ---------------------------------------------------------------------------
7854 
7856 {
7857  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7858  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7859  {
7860  TrackElementAt(1351, x).TrainIDOnElement = -1;
7863  }
7864  Utilities->CallLogPop(1342);
7865 }
7866 
7867 // ---------------------------------------------------------------------------
7868 
7869 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7870 /*
7871  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7872 */
7873 {
7874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7875  AnsiString(ScreenPosV));
7876  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7877  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7878 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7879  Utilities->CallLogPop(535);
7880 }
7881 
7882 // ---------------------------------------------------------------------------
7883 
7884 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7885 /*
7886  Converts the screen position to the true (without offsets) position
7887 */
7888 {
7889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7890  AnsiString(ScreenPosV));
7891  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7892  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7893  Utilities->CallLogPop(536);
7894 }
7895 
7896 // ---------------------------------------------------------------------------
7897 
7898 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7899 {
7900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7901  AnsiString(VPosTrue));
7902  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7903  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7904  Utilities->CallLogPop(537);
7905 }
7906 
7907 // ---------------------------------------------------------------------------
7908 
7909 void TTrack::CheckMapAndTrack(int Caller) // test
7910 {
7911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7912  int Zeroes = 0;
7913  bool FoundFlag;
7914 
7915  for(unsigned int a = 0; a < TrackVector.size(); a++)
7916  {
7917  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7918  if(CheckElement.SpeedTag == 0)
7919  {
7920  Zeroes++; // zeroed elements not saved in map
7921  }
7922  else
7923  {
7924  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7925  if(!FoundFlag)
7926  {
7927  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7928  " in TrackMap, Caller=" + (AnsiString)Caller);
7929  }
7930  if(MapVecPos != (int)a)
7931  {
7932  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7933  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7934  (AnsiString)Caller);
7935  }
7936  }
7937  }
7938  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7939  {
7940  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7941  " Caller=" + (AnsiString)Caller);
7942  }
7943  Utilities->CallLogPop(538);
7944  return;
7945 }
7946 
7947 // ---------------------------------------------------------------------------
7948 
7949 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7950 {
7951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7952  bool FoundFlag;
7953  TIMPair InactivePair;
7954 
7955  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7956  {
7957  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7958  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7959  if(!FoundFlag)
7960  {
7961  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7962  " in InactiveMap, Caller=" + (AnsiString)Caller);
7963  }
7964  if((InactivePair.first != a) && (InactivePair.second != a))
7965  {
7966  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7967  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7968  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7969  }
7970  }
7971  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7972  {
7973  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7974  " Caller=" + (AnsiString)Caller);
7975  }
7976  Utilities->CallLogPop(539);
7977 }
7978 
7979 // ---------------------------------------------------------------------------
7980 
7981 void TTrack::CheckGapMap(int Caller) // test
7982 {
7983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7984  int Position1, Position2;
7985  TTrackElement TrackElement1, TrackElement2;
7986  TGapMapIterator GapMapPtr;
7987 
7988  if(!GapMap.empty())
7989  {
7990  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7991  {
7992  int HLoc1 = GapMapPtr->first.first;
7993  int VLoc1 = GapMapPtr->first.second;
7994  int HLoc2 = GapMapPtr->second.first;
7995  int VLoc2 = GapMapPtr->second.second;
7996  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7997  {
7998  throw Exception("Failed to find H & V for gap1, GapMap in error");
7999  }
8000  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
8001  {
8002  throw Exception("Failed to find H & V for gap2, GapMap in error");
8003  }
8004  if(TrackElementAt(17, Position1).TrackType != GapJump)
8005  {
8006  throw Exception("Element at Pos1 not a gap, GapMap in error");
8007  }
8008  if(TrackElementAt(18, Position2).TrackType != GapJump)
8009  {
8010  throw Exception("Element at Pos2 not a gap, GapMap in error");
8011  }
8012  }
8013  }
8014  unsigned int GapCount = 0;
8015 
8016  for(unsigned int a = 0; a < TrackVector.size(); a++)
8017  {
8018  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
8019  if(CheckElement.TrackType == GapJump)
8020  {
8021  GapCount++;
8022  }
8023  }
8024  if((GapMap.size() * 2) != GapCount)
8025  {
8026  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
8027  (AnsiString)Caller);
8028  }
8029  Utilities->CallLogPop(540);
8030 }
8031 
8032 // ---------------------------------------------------------------------------
8033 
8034 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
8035 {
8036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
8037  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
8038  {
8039  if(TrackFinished)
8040  {
8041  throw Exception("Error - TrackFinished with erase element still present");
8042  }
8043  Utilities->CallLogPop(541);
8044  return; // erased element, can't set ID
8045  }
8046  AnsiString IDString;
8047 
8048  if(TrackElement.HLoc < 0)
8049  {
8050  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8051  }
8052  else
8053  {
8054  IDString = AnsiString(TrackElement.HLoc) + "-";
8055  }
8056  if(TrackElement.VLoc < 0)
8057  {
8058  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8059  }
8060  else
8061  {
8062  IDString += AnsiString(TrackElement.VLoc);
8063  }
8064  TrackElement.ElementID = IDString;
8065  Utilities->CallLogPop(542);
8066 }
8067 
8068 // ---------------------------------------------------------------------------
8069 
8070 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8071 {
8072 // e.g. "8-13", "00008-13", "N43-N127", etc
8073  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8074  int DelimPos;
8075 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8076  {
8077  for(int x = 1; x < String.Length() + 1; x++)
8078  {
8079  if(String.IsDelimiter("-", x))
8080  {
8081  DelimPos = x;
8082  break;
8083  }
8084  if(x == String.Length())
8085  {
8086  if(GiveMessages)
8087  {
8088  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8089  }
8090  Utilities->CallLogPop(543);
8091  return(-1);
8092  }
8093  }
8094  if(DelimPos == 1)
8095  {
8096  if(GiveMessages)
8097  {
8098  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8099  }
8100  Utilities->CallLogPop(544);
8101  return(-1);
8102  }
8103  if(DelimPos == String.Length())
8104  {
8105  if(GiveMessages)
8106  {
8107  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8108  }
8109  Utilities->CallLogPop(545);
8110  return(-1);
8111  }
8112  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8113  {
8114  if(GiveMessages)
8115  {
8116  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8117  }
8118  Utilities->CallLogPop(1508);
8119  return(-1);
8120  }
8121  int HLoc, VLoc;
8122 
8123  if(String.SubString(1, 1) != "N")
8124  {
8125  for(int x = 1; x < DelimPos; x++)
8126  {
8127  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8128  {
8129  if(GiveMessages)
8130  {
8131  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8132  }
8133  Utilities->CallLogPop(546);
8134  return(-1);
8135  }
8136  }
8137  }
8138  if(String.SubString(1, 1) == "N")
8139  {
8140  for(int x = 2; x < DelimPos; x++)
8141  {
8142  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8143  {
8144  if(GiveMessages)
8145  {
8146  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8147  }
8148  Utilities->CallLogPop(763);
8149  return(-1);
8150  }
8151  }
8152  }
8153  if(String.SubString(1, 1) == "N")
8154  {
8155  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8156  }
8157  else
8158  {
8159  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8160  }
8161  if(String.SubString(DelimPos + 1, 1) != "N")
8162  {
8163  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8164  {
8165  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8166  {
8167  if(GiveMessages)
8168  {
8169  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8170  }
8171  Utilities->CallLogPop(547);
8172  return(-1);
8173  }
8174  }
8175  }
8176  if(String.SubString(DelimPos + 1, 1) == "N")
8177  {
8178  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8179  {
8180  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8181  {
8182  if(GiveMessages)
8183  {
8184  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8185  }
8186  Utilities->CallLogPop(764);
8187  return(-1);
8188  }
8189  }
8190  }
8191  if(String.SubString(DelimPos + 1, 1) == "N")
8192  {
8193  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8194  }
8195  else
8196  {
8197  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8198  }
8199  THVPair HVPair(HLoc, VLoc);
8200  TTrackMapIterator TrackMapPtr;
8201 
8202  TrackMapPtr = TrackMap.find(HVPair);
8203  if(TrackMapPtr == TrackMap.end())
8204  {
8205  if(GiveMessages)
8206  {
8207  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8208  }
8209  Utilities->CallLogPop(548);
8210  return(-1);
8211  }
8212  Utilities->CallLogPop(549);
8213  return(TrackMapPtr->second);
8214  }
8215  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8216  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8217  {
8218  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8219  Utilities->CallLogPop(2481);
8220  return(-1);
8221  }
8222 }
8223 
8224 // ---------------------------------------------------------------------------
8225 
8226 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8227 /*
8228  True for linked properly at both ends
8229 */
8230 {
8231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8232  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8233  int HLoc = TrackElement.HLoc;
8234  int VLoc = TrackElement.VLoc;
8235 
8236  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8237  {
8238  Utilities->CallLogPop(1821);
8239  return(false);
8240  }
8241  if(TrackElement.SpeedTag == 129) // vertical footbridge
8242  {
8243  // check top connection
8244  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8245  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8246  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8247  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8248  {
8249  Utilities->CallLogPop(550);
8250  return(false);
8251  }
8252  // check bottom connection
8253  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8254  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8255  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8256  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8257  {
8258  Utilities->CallLogPop(551);
8259  return(false);
8260  }
8261  }
8262  if(TrackElement.SpeedTag == 145) // vertical underpass
8263  {
8264  // check top connection
8265  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8266  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8267  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8268  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8269  {
8270  Utilities->CallLogPop(2114);
8271  return(false);
8272  }
8273  // check bottom connection
8274  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8275  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8276  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8277  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8278  {
8279  Utilities->CallLogPop(2115);
8280  return(false);
8281  }
8282  }
8283  if(TrackElement.SpeedTag == 130) // hor footbridge
8284  {
8285  // check left connection
8286  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8287  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8288  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8289  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8290  {
8291  Utilities->CallLogPop(552);
8292  return(false);
8293  }
8294  // check right connection
8295  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8296  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8297  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8298  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8299  {
8300  Utilities->CallLogPop(553);
8301  return(false);
8302  }
8303  }
8304  if(TrackElement.SpeedTag == 146) // hor u'pass
8305  {
8306  // check left connection
8307  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8308  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8309  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8310  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8311  {
8312  Utilities->CallLogPop(2116);
8313  return(false);
8314  }
8315  // check right connection
8316  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8317  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8318  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8319  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8320  {
8321  Utilities->CallLogPop(2117);
8322  return(false);
8323  }
8324  }
8325  Utilities->CallLogPop(554);
8326  return(true);
8327 }
8328 
8329 // ---------------------------------------------------------------------------
8330 
8331 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8332 /*
8333  return true if the SpeedTag present in the map at H & V
8334 */
8335 {
8336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8337  AnsiString(SpeedTag));
8338  if(InactiveTrack2MultiMap.empty())
8339  {
8340  Utilities->CallLogPop(555);
8341  return(false);
8342  }
8343  THVPair HVPair(HLoc, VLoc);
8345  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8346  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8347 
8348  if(HVRange.first == HVRange.second)
8349  {
8350  Utilities->CallLogPop(556);
8351  return(false);
8352  }
8353  else
8354  {
8355  HVIt1 = HVRange.first;
8356  }
8357  TTrackElement Temp1, Temp2; // test
8358 
8359  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8360  if(--HVRange.second != HVRange.first)
8361  {
8362  HVIt2 = HVRange.second;
8363  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8364  }
8365  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8366  HVIt2->second).SpeedTag == SpeedTag)))
8367  {
8368  Utilities->CallLogPop(557);
8369  return(true);
8370  }
8371  else
8372  {
8373  Utilities->CallLogPop(558);
8374  return(false);
8375  }
8376 }
8377 
8378 // ---------------------------------------------------------------------------
8379 
8380 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8381 /*
8382  return true if the SpeedTag present in the map at H & V
8383 */
8384 {
8385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8386  AnsiString(SpeedTag));
8387  if(TrackMap.empty())
8388  {
8389  Utilities->CallLogPop(559);
8390  return(false);
8391  }
8392  THVPair HVPair(HLoc, VLoc);
8393  TTrackMapIterator End = TrackMap.end();
8394  TTrackMapIterator It = End;
8395 
8396  It = TrackMap.find(HVPair);
8397  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8398  {
8399  Utilities->CallLogPop(560);
8400  return(true);
8401  }
8402  else
8403  {
8404  Utilities->CallLogPop(561);
8405  return(false);
8406  }
8407 }
8408 
8409 // ---------------------------------------------------------------------------
8410 
8411 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8412 {
8413 /*
8414  General:
8415  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8416  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8417  a NamedNonStationLocation.
8418  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8419  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8420  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8421  platform at that location).
8422 
8423  Linked named location elements are those explained in TTrack::TTrack()
8424 
8425  Detail:
8426  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8427  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8428  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8429  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8430  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8431  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8432 
8433  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8434  this function a single element should be in the List (normally from the user's selection but can also be from
8435  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8436  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8437  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8438  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8439  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8440  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8441  moves them into the Map. At the end all linked elements are in the Map.
8442 
8443  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8444  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8445  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8446 */
8447 
8448 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8449 // Display->FileDiagnostics(TestString);//test
8450 
8451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8452  AnsiString TestString1, TestString2; // test
8453 
8454  Track->LNDone2MultiMap.clear();
8455  if(LNPendingList.size() != 1)
8456  {
8457  throw Exception("LNPendingList size not 1 on entry");
8458  }
8459  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8460  bool FoundFlag = false, ErasedFlag = false;
8461  while(!LNPendingList.empty())
8462  {
8463  CurrentElementNumber = LNPendingList.front();
8464  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8465  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8466  int H = CurrentElement->HLoc;
8467  int V = CurrentElement->VLoc;
8468  int Tag = CurrentElement->SpeedTag;
8469  if(Tag == 76) // top plat
8470  {
8471  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8472  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8473  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8474  for(int x = 0; x < 25; x++)
8475  {
8476  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8477  {
8478  LNPendingList.insert(LNPendingList.end(), NewElement);
8479  }
8480  }
8481  }
8482  else if(Tag == 77) // bot plat
8483  {
8484  for(int x = 0; x < 25; x++)
8485  {
8486  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8487  {
8488  LNPendingList.insert(LNPendingList.end(), NewElement);
8489  }
8490  }
8491  }
8492  else if(Tag == 78) // l plat
8493  {
8494  for(int x = 0; x < 25; x++)
8495  {
8496  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8497  {
8498  LNPendingList.insert(LNPendingList.end(), NewElement);
8499  }
8500  }
8501  }
8502  else if(Tag == 79) // r plat
8503  {
8504  for(int x = 0; x < 25; x++)
8505  {
8506  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8507  {
8508  LNPendingList.insert(LNPendingList.end(), NewElement);
8509  }
8510  }
8511  }
8512  else if(Tag == 96) // conc
8513  {
8514  for(int x = 0; x < 28; x++)
8515  {
8516  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8517  {
8518  LNPendingList.insert(LNPendingList.end(), NewElement);
8519  }
8520  }
8521  }
8522  else if(Tag == 129) // vert footbridge
8523  {
8524  for(int x = 0; x < 8; x++)
8525  {
8526  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8527  {
8528  LNPendingList.insert(LNPendingList.end(), NewElement);
8529  }
8530  }
8531  }
8532  else if(Tag == 130) // hor footbridge
8533  {
8534  for(int x = 0; x < 8; x++)
8535  {
8536  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8537  {
8538  LNPendingList.insert(LNPendingList.end(), NewElement);
8539  }
8540  }
8541  }
8542  else if(Tag == 131) // named location
8543  {
8544  for(int x = 0; x < 4; x++)
8545  {
8546  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8547  {
8548  LNPendingList.insert(LNPendingList.end(), NewElement);
8549  }
8550  }
8551  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8552  {
8553  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8554  {
8555  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8556  if(GJTVPos > -1)
8557  {
8558  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8559  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8560  bool FoundFlag2 = false;
8561  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8562  if(FoundFlag2)
8563  {
8564  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8565  {
8566  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8567  {
8568  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8569  }
8570  }
8571  }
8572  }
8573  }
8574  }
8575  }
8576  else if(Tag == 145) // v u'pass
8577  {
8578  for(int x = 0; x < 8; x++)
8579  {
8580  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8581  {
8582  LNPendingList.insert(LNPendingList.end(), NewElement);
8583  }
8584  }
8585  }
8586  else if(Tag == 146) // h u'pass
8587  {
8588  for(int x = 0; x < 8; x++)
8589  {
8590  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8591  {
8592  LNPendingList.insert(LNPendingList.end(), NewElement);
8593  }
8594  }
8595  }
8596  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8597 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8598  if(AddingElements)
8599  {
8600  int HPos, VPos; // not used but needed for FindText function
8601  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8602  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8603  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8604  {
8605  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8606  if((ExistingName != "") && (ExistingName != LocationName))
8607  {
8608  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8609  {
8610  } // name not in LocationNameMultiMap, so don't erase from TextVector
8611  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8612  {
8613  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8614  {
8615  ;
8616  } // condition not used
8617 
8618  }
8619  }
8620  }
8621  }
8622  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8623  // track at that loc
8624  THVPair HVPair(H, V);
8625  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8626  LNDone2MultiMapEntry.first = HVPair;
8627  LNDone2MultiMapEntry.second = LNPendingList.front();
8628  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8629  LNPendingList.erase(LNPendingList.begin());
8630  }
8631 
8632 // search all name multimap for same name where corresponding active elements don't appear in
8633 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8634 
8635  TLocationNameMultiMapIterator SNIterator;
8636  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8637 
8638  if(SNRange.first != SNRange.second)
8639  {
8640  SNRange.first--; // now pointing to before the first
8641  SNRange.second--; // now pointing to the last
8642  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8643  {
8644  // Same elements are in Done map as in name map
8645  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8646  {
8647  ErasedFlag = true;
8648  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8649  TVIt->LocationName = "";
8650  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8651  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8652  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8653  {
8654  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8655  if(FoundFlag)
8656  {
8657  TrackElementAt(20, Position).LocationName = "";
8658  TrackElementAt(21, Position).ActiveTrackElementName = "";
8659  }
8660  }
8661  // erase name in name map
8662 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8663  }
8664  }
8665  }
8666  if(ErasedFlag)
8667  {
8669  }
8670  if(TrackFinished)
8671  {
8674  }
8675 // set here as well as in LinkTrack so don't have to link track just because a name added
8676 // if track not finished then will be set when track validated
8677 
8678 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8679 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8680 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8681 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8682 // so the error would be seen.
8683 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8684  std::pair<AnsiString, char>TempMapPair;
8685 
8686  ContinuationNameMap.clear();
8687  for(int x = 0; x < Track->TrackVectorSize(); x++)
8688  {
8689  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8690  {
8691  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8692  TempMapPair.second = 'x'; // unused
8693  ContinuationNameMap.insert(TempMapPair);
8694  }
8695  }
8696 //end of addition
8697  CheckLocationNameMultiMap(1); // test
8698  Utilities->CallLogPop(562);
8699 }
8700 
8701 // ---------------------------------------------------------------------------
8702 
8703 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8704 /*
8705  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8706  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8707 */
8708 {
8709  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8710  AnsiString(SpeedTag));
8711  if(!NamedLocationElementAt(2, HLoc, VLoc))
8712  {
8713  Utilities->CallLogPop(948);
8714  return(false);
8715  }
8716  bool FoundFlag;
8717  int Position = -1;
8718  TIMPair IMPair;
8719 
8720  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8721  {
8722  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8723  if(FoundFlag)
8724  {
8725  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8726  {
8727  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8728  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8729  // don't allow duplicates in either list, or processing takes a lot longer
8730  {
8731  FoundElement = MapPos;
8732  Utilities->CallLogPop(563);
8733  return(true);
8734  }
8735  }
8736  }
8737  }
8738  else
8739  {
8740  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8741  if(FoundFlag)
8742  {
8743  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8744  {
8745  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8746  {
8747  FoundElement = IMPair.first;
8748  Utilities->CallLogPop(564);
8749  return(true);
8750  }
8751  }
8752  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8753  {
8754  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8755  {
8756  FoundElement = IMPair.second;
8757  Utilities->CallLogPop(565);
8758  return(true);
8759  }
8760  }
8761  }
8762  }
8763  Utilities->CallLogPop(566);
8764  return(false);
8765 }
8766 
8767 // ---------------------------------------------------------------------------
8768 
8769 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8770 /*
8771  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8772  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8773  with the new name
8774 */
8775 {
8776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8777  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8778 
8779  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8780  int HLoc = TrackElement->HLoc;
8781  int VLoc = TrackElement->VLoc;
8782  bool FoundFlag;
8783 
8784  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8785  // only have timetable names for adjacent platforms & named locations
8786  {
8787  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8788  if(FoundFlag)
8789  {
8790  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8791  }
8792  }
8793  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8794 
8795  if(ErrorString != "")
8796  {
8797  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8798  }
8799  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8800  CheckLocationNameMultiMap(2); // test
8801  Utilities->CallLogPop(567);
8802 }
8803 
8804 // ---------------------------------------------------------------------------
8805 
8806 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8807 /*
8808  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8809 */
8810 {
8811  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8812  if(LNDone2MultiMap.empty())
8813  {
8814  Utilities->CallLogPop(568);
8815  return(false);
8816  }
8817  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8818 
8819  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8820  {
8821  if(LNDone2MultiMapIterator->second == MapPos)
8822  {
8823  Utilities->CallLogPop(569);
8824  return(true);
8825  }
8826  }
8827  Utilities->CallLogPop(570);
8828  return(false);
8829 }
8830 
8831 // ---------------------------------------------------------------------------
8832 
8833 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8834 /*
8835  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8836 */
8837 {
8838  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8839  if(LNPendingList.empty())
8840  {
8841  Utilities->CallLogPop(571);
8842  return(false);
8843  }
8844  TLNPendingListIterator LNPendingListIterator;
8845 
8846  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8847  {
8848  if(*LNPendingListIterator == MapPos)
8849  {
8850  Utilities->CallLogPop(572);
8851  return(true);
8852  }
8853  }
8854  Utilities->CallLogPop(573);
8855  return(false);
8856 }
8857 
8858 // ---------------------------------------------------------------------------
8859 
8860 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8861 /*
8862  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8863 */
8864 {
8865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8866  THVPair HVPair(HLoc, VLoc);
8867  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8868  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8869 
8870  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8871  {
8872  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8873  {
8874  Utilities->CallLogPop(574);
8875  return(true);
8876  }
8877  }
8878  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8879  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8880  {
8881  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8882  {
8883  Utilities->CallLogPop(575);
8884  return(true);
8885  }
8886  }
8887  Utilities->CallLogPop(576);
8888  return(false);
8889 }
8890 
8891 // ---------------------------------------------------------------------------
8892 
8893 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8894 {
8895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8896  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8897  {
8898  Utilities->CallLogPop(1953);
8899  return(true);
8900  }
8901  Utilities->CallLogPop(1954);
8902  return(false);
8903 }
8904 
8905 // ---------------------------------------------------------------------------
8906 
8907 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8908 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8909 //program and used when try to save as a .rly file
8910 {
8911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8914  if(LocationNameMultiMap.empty()) //no names so no duplicates
8915  {
8916  Utilities->CallLogPop(2254);
8917  return(false);
8918  }
8919  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8920  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8921  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8922  {
8924  {
8925  if(GiveMessage)
8926  {
8927  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8928  }
8929  Utilities->CallLogPop(2255);
8930  return(true);
8931  }
8932  }
8933  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8934  {
8935  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8936  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8937  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8938  {
8940  {
8941  if(GiveMessage)
8942  {
8943  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8944  }
8945  Utilities->CallLogPop(2256);
8946  return(true);
8947  }
8948  }
8949  }
8950  Utilities->CallLogPop(2257);
8951  return(false); //OK, no duplicates
8952 }
8953 
8954 // ---------------------------------------------------------------------------
8955 
8957 {
8958  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8959  THVPair HVPair;
8960  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8961  //for use in the duplicate check
8962  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8963  {
8964  if(LNMMIt->second < 0) //active track element
8965  {
8966  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8967  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8968  }
8969  else //inactive track element
8970  {
8971  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8972  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8973  }
8974  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8975  }
8976  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8977 
8978  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8979  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8980  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8981 
8982  std::list<THVPair> HVLinkedList;
8983 
8984  //set the first value to true and add it to the list
8985  HVPairsLinkedMap.begin()->second = true;
8986  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8987  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8988  //examination
8989  THVPair HVPairUnderExamination;
8990  THVPairsLinkedMap::iterator HVPLMIt;
8991  THVPair HVPairNew;
8992  while(!HVLinkedList.empty())
8993  {
8994  HVPairUnderExamination = HVLinkedList.front();
8995  HVLinkedList.pop_front();
8996  HVPairNew.first = HVPairUnderExamination.first;
8997  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8998  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8999  if(HVPLMIt != HVPairsLinkedMap.end())
9000  {
9001  if(!HVPLMIt->second)
9002  {
9003  HVLinkedList.push_back(HVPLMIt->first);
9004  }
9005  HVPLMIt->second = true;
9006  }
9007  HVPairNew.first = HVPairUnderExamination.first - 1;
9008  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
9009  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9010  if(HVPLMIt != HVPairsLinkedMap.end())
9011  {
9012  if(!HVPLMIt->second)
9013  {
9014  HVLinkedList.push_back(HVPLMIt->first);
9015  }
9016  HVPLMIt->second = true;
9017  }
9018  HVPairNew.first = HVPairUnderExamination.first;
9019  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
9020  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9021  if(HVPLMIt != HVPairsLinkedMap.end())
9022  {
9023  if(!HVPLMIt->second)
9024  {
9025  HVLinkedList.push_back(HVPLMIt->first);
9026  }
9027  HVPLMIt->second = true;
9028  }
9029  HVPairNew.first = HVPairUnderExamination.first + 1;
9030  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
9031  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9032  if(HVPLMIt != HVPairsLinkedMap.end())
9033  {
9034  if(!HVPLMIt->second)
9035  {
9036  HVLinkedList.push_back(HVPLMIt->first);
9037  }
9038  HVPLMIt->second = true;
9039  }
9040  }
9041 
9042  //at the end if any have a false bool then the name is duplicated so return false
9043  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9044  {
9045  if(!HVPLMIt->second)
9046  {
9047  Utilities->CallLogPop(2258);
9048  return(false);
9049  }
9050  }
9051  Utilities->CallLogPop(2259);
9052  return(true);
9053 }
9054 
9055 // ---------------------------------------------------------------------------
9056 
9057 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9058 /*
9059  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9060 */
9061 
9062 {
9063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9064  if(LocationName == "")
9065  {
9066  Utilities->CallLogPop(577);
9067  return(false);
9068  }
9069 // new for v0.2b
9070 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9072  {
9073  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9074  ActiveTrackElementNameMap.clear();
9075  for(unsigned int x = 0; x < TrackVector.size(); x++)
9076  {
9077  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9078  == ContinuationNameMap.end())
9079  {
9080  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9081  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9082  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9083  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9084  }
9085  }
9087  }
9088  Utilities->CallLogPop(578);
9089  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9090 // end of new section
9091 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9092 }
9093 
9094 // ---------------------------------------------------------------------------
9095 
9096 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9097 /*
9098  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9099  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9100  new names in the vectors.
9101 */
9102 {
9103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9104  bool FoundFlag, ErasedFlag = false;
9105  TLocationNameMultiMapIterator SNIterator;
9106  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9107 
9108  if(SNRange.first != SNRange.second)
9109  {
9110  ErasedFlag = true;
9111  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9112  {
9113  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9114  TVIt->LocationName = "";
9115  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9116  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9117  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9118  {
9119  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9120  if(FoundFlag)
9121  {
9122  TrackElementAt(25, Position).LocationName = "";
9123  TrackElementAt(26, Position).ActiveTrackElementName = "";
9124  }
9125  }
9126  }
9127  }
9128  if(ErasedFlag)
9129  {
9131  }
9132  CheckLocationNameMultiMap(3); // test
9133  Utilities->CallLogPop(579);
9134 }
9135 
9136 // ---------------------------------------------------------------------------
9137 
9138 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9139 /*
9140  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9141  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9142  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9143  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9144  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9145  it is entered into LNPendingList and EnterLocationName sets all others.
9146 */
9147 {
9148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9149  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9150  LNPendingList.clear();
9151  AnsiString LocationName;
9152  int MapPos;
9153  bool FoundFlag = 0;
9154 
9155 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9156  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9157  if(FoundFlag)
9158  {
9159  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9160  if(LocationName != "")
9161  {
9162  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9163  EnterLocationName(13, LocationName, true);
9164  Utilities->CallLogPop(2251);
9165  return;
9166  }
9167  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9168  if(LocationName != "")
9169  {
9170  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9171  EnterLocationName(14, LocationName, true);
9172  Utilities->CallLogPop(2252);
9173  return;
9174  }
9175  }
9176 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9177 
9178  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9179  if(FoundFlag)
9180  {
9181  LocationName = TrackElementAt(1004, Position).LocationName;
9182  if(LocationName != "")
9183  {
9184  int ModifiedPosition = -1 - Position;
9185  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9186  EnterLocationName(15, LocationName, true);
9187  Utilities->CallLogPop(2253);
9188  return;
9189  }
9190  }
9191  if(SpeedTag == 76) // top plat
9192  {
9193  for(int x = 0; x < 25; x++)
9194  {
9195  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9196  {
9197  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9198  EnterLocationName(3, LocationName, true);
9199  break;
9200  }
9201  }
9202  }
9203  else if(SpeedTag == 77) // bot plat
9204  {
9205  for(int x = 0; x < 25; x++)
9206  {
9207  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9208  {
9209  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9210  EnterLocationName(4, LocationName, true);
9211  break;
9212  }
9213  }
9214  }
9215  else if(SpeedTag == 78) // l plat
9216  {
9217  for(int x = 0; x < 25; x++)
9218  {
9219  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9220  {
9221  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9222  EnterLocationName(5, LocationName, true);
9223  break;
9224  }
9225  }
9226  }
9227  else if(SpeedTag == 79) // r plat
9228  {
9229  for(int x = 0; x < 25; x++)
9230  {
9231  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9232  {
9233  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9234  EnterLocationName(6, LocationName, true);
9235  break;
9236  }
9237  }
9238  }
9239  else if(SpeedTag == 96) // conc
9240  {
9241  for(int x = 0; x < 28; x++)
9242  {
9243  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9244  {
9245  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9246  EnterLocationName(7, LocationName, true);
9247  break;
9248  }
9249  }
9250  }
9251  else if(SpeedTag == 129) // vert footbridge
9252  {
9253  for(int x = 0; x < 8; x++)
9254  {
9255  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9256  {
9257  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9258  EnterLocationName(8, LocationName, true);
9259  break;
9260  }
9261  }
9262  }
9263  else if(SpeedTag == 130) // hor footbridge
9264  {
9265  for(int x = 0; x < 8; x++)
9266  {
9267  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9268  {
9269  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9270  EnterLocationName(9, LocationName, true);
9271  break;
9272  }
9273  }
9274  }
9275  else if(SpeedTag == 145) // vert u'pass
9276  {
9277  for(int x = 0; x < 8; x++)
9278  {
9279  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9280  {
9281  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9282  EnterLocationName(11, LocationName, true);
9283  break;
9284  }
9285  }
9286  }
9287  else if(SpeedTag == 146) // hor u'pass
9288  {
9289  for(int x = 0; x < 8; x++)
9290  {
9291  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9292  {
9293  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9294  EnterLocationName(12, LocationName, true);
9295  break;
9296  }
9297  }
9298  }
9299  else if(SpeedTag == 131) // named location
9300  {
9301  for(int x = 0; x < 4; x++)
9302  {
9303  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9304  {
9305  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9306  EnterLocationName(10, LocationName, true);
9307  Utilities->CallLogPop(2657);
9308  return;
9309  }
9310  }
9311  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9312  {
9313  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9314  {
9315  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9316  if(GJTVPos > -1)
9317  {
9318  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9319  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9320  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9321  bool FoundFlag2 = false;
9322  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9323  if(FoundFlag2)
9324  {
9325  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9326  {
9327  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9328  EnterLocationName(16, LocationName, true);
9329  }
9330  }
9331  }
9332  }
9333  }
9334  }
9335 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9336  Utilities->CallLogPop(580);
9337 }
9338 
9339 // ---------------------------------------------------------------------------
9340 
9341 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9342 /*
9343  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9344  true if a LocationName is found, and also returns the name and the adjusted vector position.
9345 */
9346 {
9347  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9348  AnsiString(SpeedTag));
9349  bool FoundFlag;
9350  TIMPair IMPair;
9351  TTrackVectorIterator TempElement;
9352  int Position;
9353 
9354  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9355  if(FoundFlag)
9356  {
9357  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9358  {
9359  TempElement = InactiveTrackVector.begin() + IMPair.first;
9360  if(TempElement->LocationName != "")
9361  {
9362  LocationName = TempElement->LocationName;
9363  FoundElement = IMPair.first;
9364  Utilities->CallLogPop(581);
9365  return(true);
9366  }
9367  }
9368  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9369  {
9370  TempElement = InactiveTrackVector.begin() + IMPair.second;
9371  if(TempElement->LocationName != "")
9372  {
9373  LocationName = TempElement->LocationName;
9374  FoundElement = IMPair.second;
9375  Utilities->CallLogPop(582);
9376  return(true);
9377  }
9378  }
9379  }
9380  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9381  if(FoundFlag)
9382  {
9383  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9384  {
9385  TempElement = TrackVector.begin() + Position;
9386  if(TempElement->LocationName != "")
9387  {
9388  LocationName = TempElement->LocationName;
9389  FoundElement = -1 - Position;
9390  Utilities->CallLogPop(583);
9391  return(true);
9392  }
9393  }
9394  }
9395  Utilities->CallLogPop(584);
9396  return(false);
9397 }
9398 
9399 // ---------------------------------------------------------------------------
9400 
9401 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9402 {
9403 // check quantity in map & vectors match
9404  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9405  unsigned int Count = 0;
9406 
9407  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9408  {
9409  Utilities->CallLogPop(2059);
9410  return;
9411  }
9412  AnsiString SName, TName, ErrorString;
9413 
9414  for(unsigned int x = 0; x < TrackVector.size(); x++)
9415  {
9416  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9417  {
9418  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9419  {
9420  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9421  AnsiString(Caller));
9422  }
9423  Count++;
9424  }
9425  }
9426  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9427  {
9428  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9429  {
9430  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9431  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9432  {
9433  throw Exception
9434  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9435  AnsiString(Caller));
9436  }
9437  Count++;
9438  }
9439  }
9440  if(LocationNameMultiMap.size() != Count)
9441  {
9442  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9443  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9444  }
9445 // check all entries in both vectors match entries in name multimap
9447 
9448  for(unsigned int x = 0; x < TrackVector.size(); x++)
9449  {
9450  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9451  {
9452  SName = TrackElementAt(1365, x).LocationName;
9453  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9454  if(ErrorString != "")
9455  {
9456  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9457  }
9458  if(SNIt->second != -1 - (int)x)
9459  {
9460  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9461  AnsiString(Caller));
9462  }
9463  }
9464  // check corresponding platform for all Timetable entries that aren't empty
9465  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9466  TIMPair IMPair;
9467  bool FoundFlag = false;
9468  if(TName != "")
9469  {
9470  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9471  if(FoundFlag)
9472  {
9473  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9475  {
9476  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9477  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9478  }
9479  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9480  {
9481  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9482  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9483  AnsiString(Caller));
9484  }
9485  }
9486  else
9487  {
9488  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9489  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9490  }
9491  }
9492  }
9493  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9494  {
9495  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9496  {
9497  SName = InactiveTrackElementAt(148, x).LocationName;
9498  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9499  if(ErrorString != "")
9500  {
9501  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9502  }
9503  if(SNIt->second != (int)x)
9504  {
9505  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9506  AnsiString(Caller));
9507  }
9508  }
9509  }
9510  Utilities->CallLogPop(585);
9511 }
9512 
9513 // ---------------------------------------------------------------------------
9514 
9516  AnsiString &ErrorString)
9517 {
9518 /*
9519  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9520  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9521  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9522 */
9523  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9524  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9525  ErrorString = "";
9526  bool FoundFlag = false;
9527  TLocationNameMultiMapIterator SNIterator;
9528  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9529 
9530  if(SNRange.first == SNRange.second)
9531  {
9532  ErrorString = "Error, Name " + LocationName + " not found in map";
9533  Utilities->CallLogPop(586);
9534  return(SNRange.first);
9535  }
9536  else
9537  {
9538  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9539  {
9540  if(SNIterator->second < 0)
9541  {
9542  int TVPos = -1 - SNIterator->second;
9543  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9544  if(TVIt == TrackElement)
9545  {
9546  FoundFlag = true;
9547  Utilities->CallLogPop(587);
9548  return(SNIterator);
9549  }
9550  }
9551  else
9552  {
9553  int ITVPos = SNIterator->second;
9554  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9555  if(ITVIt == TrackElement)
9556  {
9557  FoundFlag = true;
9558  Utilities->CallLogPop(588);
9559  return(SNIterator);
9560  }
9561  }
9562  }
9563  }
9564  if(!FoundFlag)
9565  {
9566  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9567  }
9568  Utilities->CallLogPop(589);
9569  return(SNIterator);
9570 }
9571 
9572 // ---------------------------------------------------------------------------
9573 
9574 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9575 {
9576 /*
9577  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9578  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9579 */
9580  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9581  TLocationNameMultiMapEntry LocationNameEntry;
9582 
9583  LocationNameEntry.first = NewName;
9584  LocationNameEntry.second = SNIterator->second;
9585  LocationNameMultiMap.erase(SNIterator);
9586  LocationNameMultiMap.insert(LocationNameEntry);
9587  Utilities->CallLogPop(590);
9588 }
9589 
9590 // ---------------------------------------------------------------------------
9591 
9593 {
9594 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9595  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9596  if(Position < 0) // footcrossing
9597  {
9598  int TruePos = -1 - Position;
9599  // new check at v0.2b
9600  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9601  {
9602  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9603  }
9604  Utilities->CallLogPop(591);
9605  return (TrackVector.begin() + TruePos);
9606  }
9607  else
9608  {
9609  // new check at v0.2b
9610  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9611  {
9612  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9613  }
9614  Utilities->CallLogPop(592);
9615  return (InactiveTrackVector.begin() + Position);
9616  }
9617 }
9618 
9619 // ---------------------------------------------------------------------------
9620 
9621 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9622 {
9623 /*
9624  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9625  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9626  LocationNameMultiMap.
9627 */
9628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9629  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9630  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9631 
9632  if(!InactiveTrack2MultiMap.empty())
9633  {
9634  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9635  InactiveTrack2MultiMapIterator++)
9636  {
9637  if(InactiveTrack2MultiMapIterator->second > VecPos)
9638  {
9639  InactiveTrack2MultiMapIterator->second--;
9640  }
9641  // can't be == VecPos as that position erased
9642  }
9643  }
9644  if(!LocationNameMultiMap.empty())
9645  {
9646  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9647  LocationNameMultiMapIterator++)
9648  {
9649  if(LocationNameMultiMapIterator->second < 0)
9650  {
9651  continue; // deal with TrackVectors separately
9652  }
9653  if(LocationNameMultiMapIterator->second > (int)VecPos)
9654  {
9655  LocationNameMultiMapIterator->second--;
9656  }
9657  }
9658  }
9659  Utilities->CallLogPop(593);
9660 }
9661 
9662 // ---------------------------------------------------------------------------
9663 
9664 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9665 {
9666 /*
9667  After an element has been erased from the track vector, all the later elements are moved down one. This function
9668  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9669  LocationNameMultiMap.
9670 */
9671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9672  TTrackMapIterator TrackMapIterator;
9673  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9674 
9675  if(!TrackMap.empty())
9676  {
9677  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9678  {
9679  if(TrackMapIterator->second > VecPos)
9680  {
9681  TrackMapIterator->second--;
9682  }
9683  // can't be == VecPos as that position erased
9684  }
9685  }
9686  if(!LocationNameMultiMap.empty())
9687  {
9688  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9689  LocationNameMultiMapIterator++)
9690  {
9691  if(LocationNameMultiMapIterator->second >= 0)
9692  {
9693  continue; // deal with InactiveTrackVectors separately
9694  }
9695  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9696  // Val -1 -2 -3 -4 -5 -6 -7 -8
9697  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9698  {
9699  LocationNameMultiMapIterator->second++;
9700  }
9701  }
9702  }
9703  for(unsigned int x = 0; x < TrackVector.size(); x++)
9704  {
9705  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9706  if(TkEl.TrackType == GapJump)
9707  {
9708  // position 0 is the gap
9709  if(TkEl.Conn[0] == int(VecPos))
9710  {
9711  TkEl.Conn[0] = -1; // connected to a deleted gap
9712  continue;
9713  }
9714  if(TkEl.Conn[0] > int(VecPos))
9715  {
9716  TkEl.Conn[0]--;
9717  }
9718  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9719  {
9720  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9721  {
9722  TkEl.Conn[0] = -1;
9723  }
9724  }
9725  }
9726  }
9727  Utilities->CallLogPop(1433);
9728 }
9729 
9730 // ---------------------------------------------------------------------------
9731 
9733 /*
9734  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9735  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9736  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9737  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9738  running from -1 to -1 - n
9739 */
9740 {
9741  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9742  LocationNameMultiMap.clear();
9743  TLocationNameMultiMapEntry LocationNameEntry;
9744  TTrackElement TrackElement;
9745 
9746  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9747  {
9748  TrackElement = TrackElementAt(1376, TVPos);
9749  if(TrackElement.FixedNamedLocationElement)
9750  {
9751  LocationNameEntry.first = TrackElement.LocationName;
9752  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9753  LocationNameMultiMap.insert(LocationNameEntry);
9754  }
9755  }
9756 
9757  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9758  {
9759  TrackElement = InactiveTrackElementAt(149, ITVPos);
9760  if(TrackElement.FixedNamedLocationElement)
9761  {
9762  LocationNameEntry.first = TrackElement.LocationName;
9763  LocationNameEntry.second = ITVPos;
9764  LocationNameMultiMap.insert(LocationNameEntry);
9765  }
9766  }
9767  Utilities->CallLogPop(594);
9768 }
9769 
9770 // ---------------------------------------------------------------------------
9771 
9773 // Return true if there is a named location present in the railway
9774 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9775 {
9776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9777  TTrackVectorIterator ITVI;
9778 
9779  if(InactiveTrackVector.empty())
9780  {
9781  Utilities->CallLogPop(1343);
9782  return(false);
9783  }
9784  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9785  {
9786  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9787  {
9788  Utilities->CallLogPop(1404);
9789  return(true);
9790  }
9791  }
9792  Utilities->CallLogPop(1344);
9793  return(false);
9794 }
9795 
9796 // ---------------------------------------------------------------------------
9797 
9799 /*
9800  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9801 */
9802 {
9803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9804 // ResetDistanceElements(6);
9805  for(unsigned int x = 0; x < TrackVector.size(); x++)
9806  {
9807  TTrackElement &TE = TrackElementAt(718, x);
9810  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9811  {
9814  }
9815  }
9816 /* old function
9817  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9818  {
9819  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9820  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9821  }
9822  else
9823  {
9824  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9825  }
9826  }
9827 */
9828  Utilities->CallLogPop(617);
9829 }
9830 
9831 // ---------------------------------------------------------------------------
9832 
9833 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9834 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9835 {
9836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9837  for(unsigned int x = 0; x < TrackVector.size(); x++)
9838  {
9839  TTrackElement TempElement = TrackElementAt(1377, x);
9840  if(TempElement.Length01 > -1)
9841  {
9842  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9843  }
9844  if(TempElement.Length23 > -1)
9845  {
9846  MarkOneLength(2, TempElement, false, Disp);
9847  }
9848  }
9849  Disp->Update();
9850  Utilities->CallLogPop(618);
9851 }
9852 
9853 // ---------------------------------------------------------------------------
9854 
9855 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9856 /*
9857  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9858  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9859  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9860  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9861  track as indicated by FirstTrack (true for track01 & false for track23).
9862 */
9863 {
9864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9865  AnsiString((short)FirstTrack));
9866  bool LengthDifferent = false, SpeedDifferent = false;
9867 
9868  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9869  {
9870  Utilities->CallLogPop(619);
9871  return;
9872  }
9873  int EXArray[16][2] =
9874  {{4, 6}, {2, 8}, // horizontal & vertical
9875  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9876  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9877  {1, 9}, {3, 7}}; // forward & reverse diagonals
9878 
9879  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9880  Graphics::TBitmap *Bitmap;
9881 
9882  if(FirstTrack)
9883  {
9884  InLink = TrackElement.Link[0];
9885  OutLink = TrackElement.Link[1];
9886  }
9887  else
9888  {
9889  InLink = TrackElement.Link[2];
9890  OutLink = TrackElement.Link[3];
9891  }
9892  for(int x = 0; x < 16; x++)
9893  {
9894  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9895  {
9896  Index = x;
9897  }
9898  }
9899  if(Index == -1)
9900  {
9901  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9902  }
9903 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9904  the graphic for each of which is different because of the shape of the overbridge. The basic
9905  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9906  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9907  int BrEXArray[24][2] = {
9908  {4,6},{2,8},{1,9},{3,7},
9909  {1,9},{3,7},{1,9},{3,7},
9910  {2,8},{4,6},{2,8},{4,6}
9911 */
9912  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9913  {
9914  if(Index == 1)
9915  {
9916  if(TrackElement.SpeedTag == 49)
9917  {
9918  BrNum = 1 + 16;
9919  }
9920  else if(TrackElement.SpeedTag == 54)
9921  {
9922  BrNum = 8 + 16;
9923  }
9924  else if(TrackElement.SpeedTag == 55)
9925  {
9926  BrNum = 10 + 16;
9927  }
9928  }
9929  else if(Index == 0)
9930  {
9931  if(TrackElement.SpeedTag == 48)
9932  {
9933  BrNum = 0 + 16;
9934  }
9935  else if(TrackElement.SpeedTag == 58)
9936  {
9937  BrNum = 11 + 16;
9938  }
9939  else if(TrackElement.SpeedTag == 59)
9940  {
9941  BrNum = 9 + 16;
9942  }
9943  }
9944  else if(Index == 14)
9945  {
9946  if(TrackElement.SpeedTag == 50)
9947  {
9948  BrNum = 2 + 16;
9949  }
9950  else if(TrackElement.SpeedTag == 52)
9951  {
9952  BrNum = 4 + 16;
9953  }
9954  else if(TrackElement.SpeedTag == 57)
9955  {
9956  BrNum = 6 + 16;
9957  }
9958  }
9959  else if(Index == 15)
9960  {
9961  if(TrackElement.SpeedTag == 51)
9962  {
9963  BrNum = 3 + 16;
9964  }
9965  else if(TrackElement.SpeedTag == 53)
9966  {
9967  BrNum = 7 + 16;
9968  }
9969  else if(TrackElement.SpeedTag == 56)
9970  {
9971  BrNum = 5 + 16;
9972  }
9973  }
9974  }
9975  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9976  {
9977  GrNum = BrNum;
9978  }
9979  else
9980  {
9981  GrNum = Index;
9982  }
9983  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9984  {
9985  if(GrNum > 15) // underbridge
9986  {
9987  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9988  }
9989  else
9990  {
9991  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9992  }
9993  if(TrackElement.SpeedTag == 64)
9994  {
9995  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9996  }
9997  if(TrackElement.SpeedTag == 65)
9998  {
10000  }
10001  if(TrackElement.SpeedTag == 66)
10002  {
10004  }
10005  if(TrackElement.SpeedTag == 67)
10006  {
10008  }
10009  if(TrackElement.SpeedTag == 80)
10010  {
10011  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
10012  }
10013  if(TrackElement.SpeedTag == 81)
10014  {
10016  }
10017  if(TrackElement.SpeedTag == 82)
10018  {
10020  }
10021  if(TrackElement.SpeedTag == 83)
10022  {
10024  }
10025  if(TrackElement.SpeedTag == 84)
10026  {
10028  }
10029  if(TrackElement.SpeedTag == 85)
10030  {
10032  }
10033  if(TrackElement.SpeedTag == 86)
10034  {
10036  }
10037  if(TrackElement.SpeedTag == 87)
10038  {
10040  }
10041  if(TrackElement.SpeedTag == 129)
10042  {
10043  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10044  }
10045  if(TrackElement.SpeedTag == 130)
10046  {
10048  }
10049  }
10050 
10051  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10052  {
10053  if(GrNum > 15) // underbridge
10054  {
10055  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10056  }
10057  else
10058  {
10059  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10060  }
10061  if(TrackElement.SpeedTag == 64)
10062  {
10063  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10064  }
10065  if(TrackElement.SpeedTag == 65)
10066  {
10067  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10068  }
10069  if(TrackElement.SpeedTag == 66)
10070  {
10071  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10072  }
10073  if(TrackElement.SpeedTag == 67)
10074  {
10075  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10076  }
10077  if(TrackElement.SpeedTag == 80)
10078  {
10079  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10080  }
10081  if(TrackElement.SpeedTag == 81)
10082  {
10083  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10084  }
10085  if(TrackElement.SpeedTag == 82)
10086  {
10087  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10088  }
10089  if(TrackElement.SpeedTag == 83)
10090  {
10091  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10092  }
10093  if(TrackElement.SpeedTag == 84)
10094  {
10095  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10096  }
10097  if(TrackElement.SpeedTag == 85)
10098  {
10099  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10100  }
10101  if(TrackElement.SpeedTag == 86)
10102  {
10103  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10104  }
10105  if(TrackElement.SpeedTag == 87)
10106  {
10107  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10108  }
10109  if(TrackElement.SpeedTag == 129)
10110  {
10111  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10112  }
10113  if(TrackElement.SpeedTag == 130)
10114  {
10115  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10116  }
10117  }
10118 
10119  else // SpeedDifferent only: red - use non sig graphics
10120  {
10121  if(GrNum > 15) // underbridge
10122  {
10123  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10124  }
10125  else
10126  {
10127  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10128  }
10129  if(TrackElement.SpeedTag == 64)
10130  {
10131  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10132  }
10133  if(TrackElement.SpeedTag == 65)
10134  {
10136  }
10137  if(TrackElement.SpeedTag == 66)
10138  {
10140  }
10141  if(TrackElement.SpeedTag == 67)
10142  {
10144  }
10145  if(TrackElement.SpeedTag == 80)
10146  {
10147  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10148  }
10149  if(TrackElement.SpeedTag == 81)
10150  {
10152  }
10153  if(TrackElement.SpeedTag == 82)
10154  {
10156  }
10157  if(TrackElement.SpeedTag == 83)
10158  {
10160  }
10161  if(TrackElement.SpeedTag == 84)
10162  {
10164  }
10165  if(TrackElement.SpeedTag == 85)
10166  {
10168  }
10169  if(TrackElement.SpeedTag == 86)
10170  {
10172  }
10173  if(TrackElement.SpeedTag == 87)
10174  {
10176  }
10177  if(TrackElement.SpeedTag == 129)
10178  {
10179  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10180  }
10181  if(TrackElement.SpeedTag == 130)
10182  {
10184  }
10185  }
10186  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10187  Utilities->CallLogPop(620);
10188 }
10189 
10190 // ---------------------------------------------------------------------------
10191 
10192 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10193 /* FirstTrack = LinkPos's 0 & 1
10194  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10195 */
10196 {
10197  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10198  AnsiString((short)FirstTrack));
10199  LengthDifferent = false;
10200  SpeedDifferent = false;
10201  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10202  {
10203  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10204  {
10205  LengthDifferent = true;
10206  }
10207  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10208  {
10209  SpeedDifferent = true;
10210  }
10211  if(LengthDifferent || SpeedDifferent)
10212  {
10213  Utilities->CallLogPop(625);
10214  return(false);
10215  }
10216  Utilities->CallLogPop(626);
10217  return(true);
10218  }
10219 
10220  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10221  {
10222  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10223  {
10224  LengthDifferent = true;
10225  }
10226  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10227  {
10228  SpeedDifferent = true;
10229  }
10230  if(LengthDifferent || SpeedDifferent)
10231  {
10232  Utilities->CallLogPop(627);
10233  return(false);
10234  }
10235  Utilities->CallLogPop(628);
10236  return(true);
10237  }
10238 
10239  else // any other 1 track element, including platforms being present
10240  {
10241  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10242  {
10243  LengthDifferent = true;
10244  }
10245  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10246  {
10247  SpeedDifferent = true;
10248  }
10249  if(LengthDifferent || SpeedDifferent)
10250  {
10251  Utilities->CallLogPop(629);
10252  return(false);
10253  }
10254  Utilities->CallLogPop(630);
10255  return(true);
10256  }
10257 }
10258 
10259 // ---------------------------------------------------------------------------
10260 
10261 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10262 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10263 {
10264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10265  AnsiString(VLoc));
10266  bool FoundFlag;
10267  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10268 
10269  if(!FoundFlag)
10270  {
10271  Utilities->CallLogPop(633);
10272  return(false);
10273  }
10274  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10275  {
10276  Utilities->CallLogPop(634);
10277  return(true); // only need to check first since if second is a platform the the first must be too
10278  }
10279  else
10280  {
10281  Utilities->CallLogPop(635);
10282  return(false);
10283  }
10284 }
10285 
10286 // ---------------------------------------------------------------------------
10287 
10288 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10289 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10290 {
10291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10292  AnsiString(VLoc));
10293  bool FoundFlag;
10294  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10295 
10296  if(!FoundFlag)
10297  {
10298  Utilities->CallLogPop(636);
10299  return(false);
10300  }
10302  {
10303  Utilities->CallLogPop(637);
10304  return(true); // only need to check first since only one used for NamedNonStationLocations
10305  }
10306  else
10307  {
10308  Utilities->CallLogPop(638);
10309  return(false);
10310  }
10311 }
10312 
10313 // ---------------------------------------------------------------------------
10314 
10315 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10316 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10317  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10318  the front of train stop points for each direction.
10319  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10320  end (unless buffers at one or both ends in which case stop points are the end elements).
10321  Note that for a single element the stop point is the element itself (formula doesn't apply).
10322  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10323  repeating the procedure for every element. At the end all unused values are returned to -1.
10324  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10325 */
10326 {
10327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10328  TTrackElement TempElement, StartElement;
10329  AnsiString TempName;
10330  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10331  bool ForwardSet, ReverseSet;
10332 
10333  for(unsigned int x = 0; x < TrackVector.size(); x++)
10334  {
10335  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10337  }
10338  for(unsigned int x = 0; x < TrackVector.size(); x++)
10339  {
10340  TempElement = TrackElementAt(1380, x);
10341  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10342  {
10343  ForwardSet = false;
10344  ReverseSet = false;
10345  VecPos = x;
10346  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10347  // 2nd condition incl so don't re-examine elements with stop links set to 5
10348  {
10349  TempName = TempElement.ActiveTrackElementName;
10350  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10351  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10352  // an element linked at both ends where both links are also named elements
10353  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10354  {
10355  continue; // looking for an end element so skip this one
10356  }
10357  else // reached one end
10358  {
10359  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10360  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10361  // single named element linked at both ends, can't be continuation as platforms not allowed there
10362  {
10363  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10364  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10365  continue;
10366  }
10367  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10368  // single named buffer element (LinkPos 1 is the non-buffer end)
10369  {
10370  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10371  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10372  continue;
10373  }
10374  else
10375  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10376  // and platforms always on straight (conns 0 & 1) section of points
10377  {
10378  for(int y = 0; y < 2; y++)
10379  {
10380  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10381  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10382  /* TTrackElement Temp1 = TempElement;
10383  ***********New section, compiles but not checked - does bit below need to be else if?
10384  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10385  {
10386  //search along Dir direction until find other end, skip if Dir facing buffer end
10387  int NewDir = Dir;
10388  int NewVecPos;
10389  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10390  {
10391  NewVecPos = Temp1.Conn[NewDir];
10392  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10393  Temp1 = TrackElementAt(601, NewVecPos);
10394  }
10395  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10396  {
10397  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10398  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10399  }
10400  }
10401  ***************
10402  */
10403  // end may be linked at both ends but only one link named, or buffer with linked element named
10404  // if a buffer then the named linkpos has to be 1
10405  // already dealt with all types of single element so at least 2 linked named elements
10406  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10407  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10408  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10409  StartElement = TempElement;
10410  StartVecPos = VecPos; //this stays fixed at start of platform group
10411  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10412  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10413  EntryPos = 1 - Dir;
10414  StartEntryPos = 1 - Dir;
10415  Count = 1;
10416  // work along named elements until find the other end
10417  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10418  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10419  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10420  // all stop link pos's are set to 5
10421  {
10422  VecPos = TempElement.Conn[1 - EntryPos];
10423  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10424  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10425  EntryPos = TempEntryPos;
10426  Count++;
10427  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10428  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10429  }
10430  // here when reached other end, maybe buffers, or last named linked element
10431  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10432  // terminal station, set end elements as stop elements
10433  {
10434  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10435  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10436  continue;
10437  }
10438  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10439  // terminal station, set end elements as stop elements
10440  {
10441  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10442  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10443  continue;
10444  }
10445  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10446  ForwardNumber = ((Count + 1) / 2) + 1;
10447  ReverseNumber = (Count - ForwardNumber) + 1;
10448  Count = 1; // starting value
10449  EntryPos = 1 - Dir;
10450  TempElement = StartElement;
10451  VecPos = StartVecPos;
10452  if(Count == ForwardNumber)
10453  {
10454  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10455  ForwardSet = true;
10456  }
10457  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10458  {
10459  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10460  ReverseSet = true;
10461  }
10462  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10463  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10464  {
10465  VecPos = TempElement.Conn[1 - EntryPos];
10466  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10467  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10468  EntryPos = TempEntryPos;
10469  Count++;
10470  if(Count == ForwardNumber)
10471  {
10472  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10473  ForwardSet = true;
10474  }
10475  if(Count == ReverseNumber)
10476  {
10477  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10478  ReverseSet = true;
10479  }
10480  }
10481  }
10482  }
10483  }
10484  }
10485  }
10486  }
10487  }
10488  for(unsigned int x = 0; x < TrackVector.size(); x++)
10489  {
10490  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10491  {
10493  }
10494  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10495  {
10497  }
10498  }
10499  Utilities->CallLogPop(639);
10500 }
10501 
10502 // ---------------------------------------------------------------------------
10503 
10504 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10505 
10506 {
10507 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10508 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10509 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10510 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10511 
10512 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10513 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10514 */
10515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10516  TTrackElement TempElement;
10517  AnsiString TempName;
10518  std::list<unsigned int> NameList; //end elements
10519  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10520  for(unsigned int x = 0; x < TrackVector.size(); x++)
10521  {
10522  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10524  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10525  {
10526  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10527  }
10528  }
10529  ContinuationNameList.sort();
10530  ContinuationNameList.unique();
10531 
10532  for(unsigned int x = 0; x < TrackVector.size(); x++)
10533  {
10534  TempElement = TrackElementAt(1598, x);
10535  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10536  {
10537  bool NameIsAContinuation = false;
10538  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10539  {
10540  NameIsAContinuation = true;
10541  }
10542  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10543  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10544  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10545  {
10546  TempName = TempElement.ActiveTrackElementName;
10547  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10548  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10549  // an element linked at both ends of single or main track where both links are also named elements with same name
10550  {
10551  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10552  {
10553  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10554  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10555  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10556  {
10557  continue; //not an end element so skip it
10558  }
10559  else //reached an end on the diverging leg
10560  {
10561  NameList.push_back(x);
10562  }
10563  }
10564  else if(TempElement.TrackType == Crossover)
10565  {
10566  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10567  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10568  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10569  {
10570  continue; //not an end element so skip it
10571  }
10572  else
10573  {
10574  NameList.push_back(x);
10575  }
10576  }
10577  else
10578  {
10579  continue; //not points ot crossover & not an end element so skip
10580  }
10581  }
10582  else // reached one end of single or main track
10583  {
10584  NameList.push_back(x);
10585  }
10586 //NameList now contains all non-station end elements
10587  while(!NameList.empty())
10588  {
10589  unsigned int a = NameList.front();
10590  NameList.pop_front();
10591  TTrackElement &TempElement = TrackElementAt(1605, a);
10592  AnsiString TempName = TempElement.ActiveTrackElementName;
10593  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10594  {
10595  TempElement.StationEntryStopLinkPos1 = 1;
10596  }
10597  else
10598  {
10599  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10600  {
10601  TempElement.StationEntryStopLinkPos1 = 1;
10602  }
10603  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10604  {
10605  TempElement.StationEntryStopLinkPos2 = 0;
10606  }
10607  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10608  {
10609  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10610  {
10611  TempElement.StationEntryStopLinkPos3 = 3;
10612  }
10613  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10614  {
10615  TempElement.StationEntryStopLinkPos4 = 2;
10616  }
10617  }
10618  }
10619  }
10620  }
10621  }
10622  }
10623  Utilities->CallLogPop(2640);
10624 }
10625 
10626 // ---------------------------------------------------------------------------
10627 
10628 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10629 {
10630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10631  TTrackElement Next;
10632 
10634  while(ReturnNextInactiveTrackElement(1, Next))
10635  {
10636  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10637  {
10638  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10639  // need striped graphics
10640  {
10641  if(Next.SpeedTag == 76)
10642  {
10643  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10644  }
10645  else if(Next.SpeedTag == 77)
10646  {
10647  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10648  }
10649  else if(Next.SpeedTag == 78)
10650  {
10651  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10652  }
10653  else if(Next.SpeedTag == 79)
10654  {
10655  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10656  }
10657  else if(Next.SpeedTag == 96)
10658  {
10659  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10660  }
10661  else if(Next.SpeedTag == 131)
10662  {
10663  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10664  }
10665  }
10666  else
10667  {
10668  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10669  }
10670  }
10671  }
10672 
10673  NextTrackElementPtr = TrackVector.begin();
10674  while(ReturnNextTrackElement(1, Next))
10675  {
10676  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10677  {
10678  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10679  {
10680  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10681  {
10682  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10683  }
10684  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10685  {
10686  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10687  }
10688  }
10689  else
10690  {
10691  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10692  }
10693  }
10694  }
10695  Disp->Update();
10696  Utilities->CallLogPop(640);
10697 }
10698 
10699 // ---------------------------------------------------------------------------
10700 
10701 void TTrack::PlotSmallRedGap(int Caller)
10702 {
10703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10705  Utilities->CallLogPop(1346);
10706 }
10707 
10708 // ---------------------------------------------------------------------------
10709 
10710 void TTrack::TrackClear(int Caller)
10711 {
10712  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10713  TrackVector.clear();
10714  InactiveTrackVector.clear();
10715  TrackMap.clear();
10717  if(TextHandler->TextVector.size() == 0)
10718  {
10719  Display->DisplayOffsetH = 0;
10720  Display->DisplayOffsetV = 0;
10727  HLocMin = 2000000000;
10728  HLocMax = -2000000000;
10729  VLocMin = 2000000000;
10730  VLocMax = -2000000000;
10731  }
10732  else
10733  {
10734  CalcHLocMinEtc(4);
10735  }
10736  Utilities->CallLogPop(1347);
10737 }
10738 
10739 // ---------------------------------------------------------------------------
10740 
10741 void TTrack::CalcHLocMinEtc(int Caller)
10742 {
10743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10744  HLocMin = 2000000000;
10745  VLocMin = 2000000000;
10746  HLocMax = -2000000000;
10747  VLocMax = -2000000000;
10748  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10749  {
10750  if(TrackElementAt(1385, x).SpeedTag == 0)
10751  {
10752  continue; // skip erase elements or would interfere with Min & Max values
10753  }
10754  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10755  {
10756  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10757  }
10758  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10759  {
10760  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10761  }
10762  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10763  {
10764  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10765  }
10766  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10767  {
10768  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10769  }
10770  }
10771  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10772  {
10773  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10774  {
10775  continue; // shouldn't be any inactive erase elements but include anyway
10776  }
10777  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10778  {
10779  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10780  }
10781  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10782  {
10783  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10784  }
10785  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10786  {
10787  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10788  }
10789  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10790  {
10791  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10792  }
10793  }
10794  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10795  {
10796 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10797  will fail as x will exceed the maximum value
10798  if(TextHandler->TextPtrAt(, x)->TextString == "")
10799  {
10800  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10801  }
10802 */
10803  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10804  if((TextH / 16) - 1 < HLocMin)
10805  {
10806  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10807  }
10808  if((TextH / 16) + 1 > HLocMax)
10809  {
10810  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10811  }
10812  if((TextV / 16) - 1 < VLocMin)
10813  {
10814  VLocMin = (TextV / 16) - 1;
10815  }
10816  if((TextV / 16) + 1 > VLocMax)
10817  {
10818  VLocMax = (TextV / 16) + 1;
10819  }
10820  }
10821  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10822  {
10823  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10824  {
10825  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10826  }
10827  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10828  {
10829  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10830  }
10831  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10832  {
10833  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10834  }
10835  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10836  {
10837  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10838  }
10839  }
10840 
10841  Utilities->CallLogPop(641);
10842 }
10843 
10844 // ---------------------------------------------------------------------------
10845 
10846 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10847  bool &UserGraphicFoundFlag)
10848 {
10849  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10850  TUserGraphicVector::iterator UserGraphicPtr;
10851 
10852  UserGraphicFoundFlag = false;
10853  if(!UserGraphicVector.empty())
10854  {
10855  int x = UserGraphicVector.size();
10856  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10857  {
10858  x--;
10859  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10860  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10861  {
10862  UserGraphicItem = x;
10863  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10864  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10865  UserGraphicFoundFlag = true;
10866  Utilities->CallLogPop(2177);
10867  return;
10868  } // if ....
10869 
10870  } // for UserGraphicPtr...
10871  } // if !UserGraphicVector...
10872 
10873  Utilities->CallLogPop(2197);
10874 }
10875 
10876 // ---------------------------------------------------------------------------
10877 
10879 {
10880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10881  TrackElement.LogTrack(11));
10882  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10883  int SpeedTag = TrackElement.SpeedTag;
10884 
10885  if(SpeedTag < 1)
10886  {
10887  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10888  }
10889  switch(SpeedTag)
10890  {
10891  case 76: // t platform
10892  GraphicOutput = RailGraphics->gl76Striped;
10893  break;
10894 
10895  case 77: // h platform
10896  GraphicOutput = RailGraphics->bm77Striped;
10897  break;
10898 
10899  case 78: // v platform
10900  GraphicOutput = RailGraphics->bm78Striped;
10901  break;
10902 
10903  case 79: // r platform
10904  GraphicOutput = RailGraphics->gl79Striped;
10905  break;
10906 
10907  case 96: // concourse
10908  GraphicOutput = RailGraphics->ConcourseStriped;
10909  break;
10910 
10911  case 129: // v footbridge
10912  GraphicOutput = RailGraphics->gl129Striped;
10913  break;
10914 
10915  case 130: // h footbridge
10916  GraphicOutput = RailGraphics->gl130Striped;
10917  break;
10918 
10919  case 131: // non-station named loc
10920  GraphicOutput = RailGraphics->bmNameStriped;
10921  break;
10922 
10923  case 145: // v u'pass
10924  GraphicOutput = RailGraphics->gl145Striped;
10925  break;
10926 
10927  case 146: // h u'pass
10928  GraphicOutput = RailGraphics->gl146Striped;
10929  break;
10930 
10931  default:
10932  GraphicOutput = TrackElement.GraphicPtr;
10933  break;
10934  }
10935  Utilities->CallLogPop(642);
10936  return(GraphicOutput);
10937 }
10938 
10939 // ---------------------------------------------------------------------------
10940 
10942 {
10943  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10944  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10945  {
10946 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10947  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10948  }
10949  Utilities->CallLogPop(643);
10950  return(TrackVector.at(At));
10951 }
10952 
10953 // ---------------------------------------------------------------------------
10954 
10956 {
10957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10958  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10959  {
10960  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10961  " in InactiveTrackElementAt");
10962  }
10963  Utilities->CallLogPop(644);
10964  return(InactiveTrackVector.at(At));
10965 }
10966 
10967 // ---------------------------------------------------------------------------
10968 
10969 bool TTrack::BlankElementAt(int Caller, int At) const
10970 {
10971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10972  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10973  {
10974  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10975  }
10976  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10977  {
10978  Utilities->CallLogPop(645);
10979  return(true);
10980  }
10981  else
10982  {
10983  Utilities->CallLogPop(646);
10984  return(false);
10985  }
10986 }
10987 
10988 // ---------------------------------------------------------------------------
10989 
10990 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
10991 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10992  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10993  split is required a specific check is made using ThisStationLongEnoughForSplit.
10994  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10995  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10996 */
10997 {
10998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
10999  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11000  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
11001  TLocationNameMultiMapIterator SNIterator;
11002  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11003 
11004  if(SNRange.first == SNRange.second)
11005  {
11006  Utilities->CallLogPop(972);
11007  return(false); // should have been caught earlier but include for completeness
11008  }
11009  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11010  {
11011  if(SNIterator->second < 0)
11012  {
11013  continue; // exclude footcrossings
11014  }
11015  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
11016  if(InactiveElement.TrackType == Concourse)
11017  {
11018  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11019  }
11020  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11021  {
11022  continue; // only interested in locations where ActiveTrackElementName may be set
11023  }
11024  THVPair HVPair;
11025  HVPair.first = InactiveElement.HLoc;
11026  HVPair.second = InactiveElement.VLoc;
11027  if(TrackMap.find(HVPair) == TrackMap.end())
11028  {
11029  throw Exception
11030  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
11031  }
11032  int TVPos = TrackMap.find(HVPair)->second;
11033  FirstNamedElement = TrackElementAt(560, TVPos);
11034  // first check linked on both sides, skip the check if not
11035  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11036  {
11037  continue;
11038  }
11039  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11040  // ActiveTrackElementNames are points and excluding trailing connections for points
11041  FirstNamedExitPos = 0;
11042  {
11043  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11044  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11045  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11046  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11047  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11048  {
11049  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11050  {
11051  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11052  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11053  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11054  // success, now check FirstNamedElement link not trailing points & if so all OK
11055  {
11056  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11057  {
11058  Utilities->CallLogPop(1002);
11059  return(true);
11060  }
11061  }
11062  }
11063  }
11064  }
11065  // failed, try link 1
11066  FirstNamedExitPos = 1;
11067  {
11068  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11069  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11070  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11071  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11072  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11073  {
11074  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11075  {
11076  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11077  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11078  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11079  // success, now check FirstNamedElement link not trailing points & if so all OK
11080  {
11081  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11082  {
11083  Utilities->CallLogPop(1003);
11084  return(true);
11085  }
11086  }
11087  }
11088  }
11089  }
11090  }
11091  Utilities->CallLogPop(1004);
11092  return(false);
11093 }
11094 
11095 // ---------------------------------------------------------------------------
11096 
11097 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName) //changed at v2.18.0
11098 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11099  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11100  split is required a specific check is made using ThisLocationLongEnoughForSplit.
11101  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11102  buffers explicitly as it will come out automatically with the logic applied.
11103  Note that these conditions exclude opposed buffers since these not linked.
11104 */
11105 {
11106  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11107  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11108  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11109  TLocationNameMultiMapIterator SNIterator;
11110  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11111 
11112  if(SNRange.first == SNRange.second)
11113  {
11114  Utilities->CallLogPop(2641);
11115  return(false); // should have been caught earlier but include for completeness
11116  }
11117  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11118  {
11119  if(SNIterator->second < 0) //negative numbers represent active track elements
11120  {
11121  continue; // exclude footcrossings - only these have active track element names
11122  }
11123  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11124  if(InactiveElement.TrackType == Concourse)
11125  {
11126  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11127  }
11128  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11129  {
11130  continue; // only interested in locations where ActiveTrackElementName may be set
11131  }
11132  THVPair HVPair;
11133  HVPair.first = InactiveElement.HLoc;
11134  HVPair.second = InactiveElement.VLoc;
11135  if(TrackMap.find(HVPair) == TrackMap.end())
11136  {
11137  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11138  }
11139  int TVPos = TrackMap.find(HVPair)->second;
11140  FirstNamedElement = TrackElementAt(1610, TVPos);
11141  // first check linked on both sides, skip the check if not
11142  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11143  {
11144  continue;
11145  }
11146  // check if another ActiveTrackElementName connected via a link
11147  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11148  {
11149  FirstNamedExitPos = 0; //this is the end linked to the second named element
11150  {
11151  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11152  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11153  {
11154  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11155  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11156  {
11157  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11158  }
11159  else if(SecondNamedEntryPos == 2)
11160  {
11161  SecondNamedExitPos = 3;
11162  }
11163  else if(SecondNamedEntryPos == 3)
11164  {
11165  SecondNamedExitPos = 2;
11166  }
11167  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11168  {
11169  Utilities->CallLogPop(2642);
11170  return(true);
11171  } //if not try other exitpos
11172  }
11173  }
11174  FirstNamedExitPos = 1;
11175  {
11176  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11177  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11178  {
11179  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11180  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11181  {
11182  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11183  }
11184  else if(SecondNamedEntryPos == 2)
11185  {
11186  SecondNamedExitPos = 3;
11187  }
11188  else if(SecondNamedEntryPos == 3)
11189  {
11190  SecondNamedExitPos = 2;
11191  }
11192  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11193  {
11194  Utilities->CallLogPop(2643);
11195  return(true);
11196  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11197  }
11198  }
11199  }
11200  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11201  {
11202  FirstNamedExitPos = 2;
11203  {
11204  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11205  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11206  {
11207  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11208  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11209  {
11210  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11211  }
11212  else if(SecondNamedEntryPos == 2)
11213  {
11214  SecondNamedExitPos = 3;
11215  }
11216  else if(SecondNamedEntryPos == 3)
11217  {
11218  SecondNamedExitPos = 2;
11219  }
11220  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11221  {
11222  Utilities->CallLogPop(2644);
11223  return(true);
11224  } //if not try other exitpos
11225  }
11226  }
11227  FirstNamedExitPos = 3;
11228  {
11229  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11230  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11231  {
11232  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11233  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11234  {
11235  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11236  }
11237  else if(SecondNamedEntryPos == 2)
11238  {
11239  SecondNamedExitPos = 3;
11240  }
11241  else if(SecondNamedEntryPos == 3)
11242  {
11243  SecondNamedExitPos = 2;
11244  }
11245  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11246  {
11247  Utilities->CallLogPop(2645);
11248  return(true);
11249  } //failed so continue to next element or return false
11250  }
11251  }
11252  }
11253  }
11254  Utilities->CallLogPop(2646);
11255  return(false);
11256 }
11257 
11258 // ---------------------------------------------------------------------------
11259 
11260 //new version at v2.18.0
11261 bool TTrack::ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement,
11262  int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
11263 /* Return false if the track that the train is on isn't long enough for a split - only 1 named element or 2 with only one external link.
11264 Otherwise find the best 4 final element positions, preferably with FrontTrainFrontPos on a named element. Conditions are that the original train
11265 will lie within the 4 elements of the two split trains, and at least 1 element of each split train will be at the location. Within those conditions
11266 the lead element of the front train will be at the location if it is possible.
11267 */
11268 {
11269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisLocationLongEnoughForSplit," + AnsiString(TrainID) + "," +
11270  LocationName + AnsiString(LeadElement) + "," + AnsiString(LeadExitPos) + "," + AnsiString(MidElement) + "," + AnsiString(MidEntryPos));
11271 
11272  TemporaryDelay = false; //used in calling function to set LastActionTime to TTClockTime so failure messages only given every 30 secs
11273  //count forwards from LeadElement - only need to count forwards 2 elements to ptovide for room for new front train
11274  int FwdPos[3] = {LeadElement, -1, -1}; //0 starts at LeadElement and increases as go forwards
11275  int RwdPos[3] = {MidElement, -1, -1}; //0 starts at MidElement and increases as go backwards
11276  TTrackElement FwdPos0Element = TrackElementAt(1666, LeadElement);
11277  TTrackElement RwdPos0Element = TrackElementAt(1667, MidElement);
11278  int FwdPos1EntryPos, FwdPos1ExitPos, FwdPos2EntryPos, FwdPos2ExitPos, RwdPos1EntryPos, RwdPos1ExitPos, RwdPos2EntryPos, RwdPos2ExitPos; //these needed to test for other train on element
11279 
11280  bool FwdDerail1 = false, FwdDerail2 = false, RwdDerail1 = false, RwdDerail2 = false;
11281  int NumFwdNamedElements = 0, NumFwdElements = 0, NumRwdNamedElements = 0, NumRwdElements = 1; //Fwd = ahead of LeadElement, Rwd includes MidElement
11282  if(RwdPos0Element.ActiveTrackElementName == LocationName) //MidElement
11283  {
11284  NumRwdNamedElements = 1;
11285  }
11286 
11287  FwdPos[1] = FwdPos0Element.Conn[LeadExitPos];
11288  if(FwdPos[1] > -1)
11289  {
11290  NumFwdElements = 1;
11291  TTrackElement FwdPos1Element = TrackElementAt(1668, FwdPos[1]);
11292  if(FwdPos1Element.ActiveTrackElementName == LocationName)
11293  {
11294  NumFwdNamedElements = 1;
11295  }
11296  FwdPos1EntryPos = FwdPos0Element.ConnLinkPos[LeadExitPos];
11297  FwdPos1ExitPos = GetAnyElementOppositeLinkPos(4, FwdPos[1], FwdPos1EntryPos, FwdDerail1);
11298  FwdPos[2] = FwdPos1Element.Conn[FwdPos1ExitPos];
11299  if(FwdPos[2] > -1)
11300  {
11301  NumFwdElements = 2;
11302  FwdPos2EntryPos = FwdPos1Element.ConnLinkPos[FwdPos1ExitPos];
11303  FwdPos2ExitPos = GetAnyElementOppositeLinkPos(5, FwdPos[2], FwdPos2EntryPos, FwdDerail2); //this is purely to obtain Derail
11304  TTrackElement FwdPos2Element = TrackElementAt(1669, FwdPos[2]);
11305  if(FwdPos2Element.ActiveTrackElementName == LocationName)
11306  {
11307  NumFwdNamedElements = 2;
11308  }
11309  }
11310  }
11311 //this is as far as need to go forwards
11312 
11313  RwdPos[1] = RwdPos0Element.Conn[MidEntryPos];
11314  if(RwdPos[1] > -1)
11315  {
11316  NumRwdElements = 2; //includes MidElement
11317  TTrackElement RwdPos1Element = TrackElementAt(1670, RwdPos[1]);
11318  if(RwdPos1Element.ActiveTrackElementName == LocationName)
11319  {
11320  NumRwdNamedElements = 2; //includes MidElement (treats MidElement as named even if not, as eventual positions will be same either way)
11321  }
11322  RwdPos1ExitPos = RwdPos0Element.ConnLinkPos[MidEntryPos];
11323  RwdPos1EntryPos = GetAnyElementOppositeLinkPos(6, RwdPos[1], RwdPos1ExitPos, RwdDerail1);
11324  RwdPos[2] = RwdPos1Element.Conn[RwdPos1EntryPos];
11325  if(RwdPos[2] > -1)
11326  {
11327  NumRwdElements = 3; //includes MidElement
11328  RwdPos2ExitPos = RwdPos1Element.ConnLinkPos[RwdPos1EntryPos];
11329  RwdPos2EntryPos = GetAnyElementOppositeLinkPos(7, RwdPos[2], RwdPos2ExitPos, RwdDerail2); //this is purely to obtain Derail
11330  TTrackElement RwdPos2Element = TrackElementAt(1671, RwdPos[2]);
11331  if(RwdPos2Element.ActiveTrackElementName == LocationName)
11332  {
11333  NumRwdNamedElements = 3; //includes MidElement (treats MidElement & next position to rear as both named even if not, as eventual positions will be same either way)
11334  }
11335  }
11336  }
11337 //this is as far as need to go backwards
11338 
11339 //now try to accommodate front train on named elements if possible
11340  if(NumFwdNamedElements == 2)//Front train moves onto the 2 forward named elements & rear train is on original train elements X N N N (N = named, X = named or not)
11341  { // M L - - >> RM RL FM FL
11342  FrontTrainFrontPos = FwdPos[2];
11343  FrontTrainRearPos = FwdPos[1];
11344  RearTrainFrontPos = LeadElement;
11345  RearTrainRearPos = MidElement;
11346  if(FwdDerail1 || FwdDerail2)
11347  {
11348  TrainController->StopTTClockMessage(159, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11349  TemporaryDelay = true;
11350  Utilities->CallLogPop(2661); //may be able to split further back but leave as is to avoid complication
11351  return(true);
11352  }
11353  if(OtherTrainOnTrack(6, FwdPos[1], FwdPos1EntryPos, TrainID))
11354  {
11355  TrainController->StopTTClockMessage(160, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11356  TemporaryDelay = true;
11357  Utilities->CallLogPop(2662); //may be able to split further back but leave as is to avoid complication
11358  return(true);
11359  }
11360  if(OtherTrainOnTrack(7, FwdPos[2], FwdPos2ExitPos, TrainID))
11361  {
11362  TrainController->StopTTClockMessage(161, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11363  TemporaryDelay = true;
11364  Utilities->CallLogPop(2663); //may be able to split further back but leave as is to avoid complication
11365  return(true);
11366  }
11367  Utilities->CallLogPop(2664);
11368  return(true);
11369  }
11370 
11371  else if((NumFwdNamedElements == 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11372  { //Front train moves onto the 1 forward named element & rear train occupies 1 element behind original train - M L - >> RM RL FM FL
11373  FrontTrainFrontPos = FwdPos[1];
11374  FrontTrainRearPos = LeadElement;
11375  RearTrainFrontPos = MidElement;
11376  RearTrainRearPos = RwdPos[1];
11377  if(FwdDerail1)
11378  {
11379  TrainController->StopTTClockMessage(162, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11380  TemporaryDelay = true;
11381  Utilities->CallLogPop(2665); //may be able to split further back but leave as is to avoid complication
11382  return(true);
11383  }
11384  if(RwdDerail1)
11385  {
11386  TrainController->StopTTClockMessage(163, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11387  TemporaryDelay = true;
11388  Utilities->CallLogPop(2666); //may be able to split further back but leave as is to avoid complication
11389  return(true);
11390  }
11391  if(OtherTrainOnTrack(8, FwdPos[1], FwdPos1EntryPos, TrainID))
11392  {
11393  TrainController->StopTTClockMessage(164, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11394  TemporaryDelay = true;
11395  Utilities->CallLogPop(2667); //may be able to split further back but leave as is to avoid complication
11396  return(true);
11397  }
11398  if(OtherTrainOnTrack(9, RwdPos[1], RwdPos1ExitPos, TrainID))
11399  {
11400  TrainController->StopTTClockMessage(165, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11401  TemporaryDelay = true;
11402  Utilities->CallLogPop(2668); //may be able to split further back but leave as is to avoid complication
11403  return(true);
11404  }
11405  Utilities->CallLogPop(2669);
11406  return(true);
11407  }
11408 
11409  else if((NumRwdNamedElements >= 2) && (NumRwdElements == 3)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11410  {//front train occupies original train position and rear train fits behind it - - M L >> RM RL FM FL
11411  FrontTrainFrontPos = LeadElement;
11412  FrontTrainRearPos = MidElement;
11413  RearTrainFrontPos = RwdPos[1];
11414  RearTrainRearPos = RwdPos[2];
11415  if(RwdDerail1 || RwdDerail2)
11416  {
11417  TrainController->StopTTClockMessage(166, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11418  TemporaryDelay = true;
11419  Utilities->CallLogPop(2670); //may be able to split further back but leave as is to avoid complication
11420  return(true);
11421  }
11422  if(OtherTrainOnTrack(10, RwdPos[1], RwdPos1ExitPos, TrainID))
11423  {
11424  TrainController->StopTTClockMessage(167, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11425  TemporaryDelay = true;
11426  Utilities->CallLogPop(2671); //may be able to split further back but leave as is to avoid complication
11427  return(true);
11428  }
11429  if(OtherTrainOnTrack(11, RwdPos[2], RwdPos2EntryPos, TrainID))
11430  {
11431  TrainController->StopTTClockMessage(168, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11432  TemporaryDelay = true;
11433  Utilities->CallLogPop(2672); //may be able to split further back but leave as is to avoid complication
11434  return(true);
11435  }
11436  Utilities->CallLogPop(2673);
11437  return(true);
11438  }
11439 
11440 //here look for front overhang situations
11441  else if((NumFwdNamedElements == 1) && (NumFwdElements == 2)) // X N N X (N = named, X = named or not but connected)
11442  { // M L - - >> RM RL FM FL
11443  FrontTrainFrontPos = FwdPos[2];
11444  FrontTrainRearPos = FwdPos[1];
11445  RearTrainFrontPos = LeadElement;
11446  RearTrainRearPos = MidElement;
11447  if(FwdDerail1 || FwdDerail2)
11448  {
11449  TrainController->StopTTClockMessage(169, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11450  TemporaryDelay = true;
11451  Utilities->CallLogPop(2674); //may be able to split further back but leave as is to avoid complication
11452  return(true);
11453  }
11454  if(OtherTrainOnTrack(12, FwdPos[1], FwdPos1EntryPos, TrainID))
11455  {
11456  TrainController->StopTTClockMessage(170, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11457  TemporaryDelay = true;
11458  Utilities->CallLogPop(2675); //may be able to split further back but leave as is to avoid complication
11459  return(true);
11460  }
11461  if(OtherTrainOnTrack(13, FwdPos[2], FwdPos2ExitPos, TrainID))
11462  {
11463  TrainController->StopTTClockMessage(171, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11464  TemporaryDelay = true;
11465  Utilities->CallLogPop(2676); //may be able to split further back but leave as is to avoid complication
11466  return(true);
11467  }
11468  Utilities->CallLogPop(2677);
11469  return(true);
11470  }
11471 
11472  else if((NumFwdElements >= 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) // X N N X (N = named, X = named or not but connected)
11473  { // - M L - >> RM RL FM FL
11474  FrontTrainFrontPos = FwdPos[1];
11475  FrontTrainRearPos = LeadElement;
11476  RearTrainFrontPos = MidElement;
11477  RearTrainRearPos = RwdPos[1];
11478  if(FwdDerail1)
11479  {
11480  TrainController->StopTTClockMessage(172, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11481  TemporaryDelay = true;
11482  Utilities->CallLogPop(2678); //may be able to split further back but leave as is to avoid complication
11483  return(true);
11484  }
11485  if(RwdDerail1)
11486  {
11487  TrainController->StopTTClockMessage(173, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11488  TemporaryDelay = true;
11489  Utilities->CallLogPop(2679); //may be able to split further back but leave as is to avoid complication
11490  return(true);
11491  }
11492  if(OtherTrainOnTrack(14, FwdPos[1], FwdPos1EntryPos, TrainID))
11493  {
11494  TrainController->StopTTClockMessage(174, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11495  TemporaryDelay = true;
11496  Utilities->CallLogPop(2680); //may be able to split further back but leave as is to avoid complication
11497  return(true);
11498  }
11499  if(OtherTrainOnTrack(15, RwdPos[1], RwdPos1ExitPos, TrainID))
11500  {
11501  TrainController->StopTTClockMessage(175, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11502  TemporaryDelay = true;
11503  Utilities->CallLogPop(2681); //may be able to split further back but leave as is to avoid complication
11504  return(true);
11505  }
11506  Utilities->CallLogPop(2682);
11507  return(true);
11508  }
11509 //anything else fails as location too short
11510  Utilities->CallLogPop(2652);
11511  return(false);
11512 }
11513 
11514 // ---------------------------------------------------------------------------
11515 
11516 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11517 {
11518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11519  TLocationNameMultiMapIterator SNIterator;
11520  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11521 
11522  if(SNRange.first != SNRange.second)
11523  {
11524  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11525  {
11526  if(SNIterator->second < 0)
11527  {
11528  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11529  }
11530  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11531  SNIterator->second).TrackType == NamedNonStationLocation))
11532  {
11533  Utilities->CallLogPop(1121);
11534  return(true);
11535  }
11536  }
11537  }
11538  Utilities->CallLogPop(848);
11539  return(false);
11540 }
11541 
11542 // ---------------------------------------------------------------------------
11543 
11544 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11545 {
11546 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11547  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11548  "," + AnsiString(SpeedTag));
11549  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11550  {
11551  Utilities->CallLogPop(949);
11552  return(false);
11553  }
11554  bool FoundFlag;
11555  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11556 
11557  if(!FoundFlag)
11558  {
11559  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11560  }
11561  TTrackElement IAElement;
11562 
11563  if(SpeedTag == 68) // top sig
11564  {
11565  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11566  {
11567  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11568  {
11569  IAElement = InactiveTrackElementAt(50, IMPair.first);
11570  }
11571  else
11572  {
11573  IAElement = InactiveTrackElementAt(51, IMPair.second);
11574  }
11575  if(IAElement.LocationName == "")
11576  {
11577 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11578  SignalPlatformGraphic = RailGraphics->gl76Striped;
11579  }
11580  else
11581  {
11582 // SignalPlatformGraphic = RailGraphics->Plat68;
11583  SignalPlatformGraphic = RailGraphics->gl76;
11584  }
11585  Utilities->CallLogPop(950);
11586  return(true);
11587  }
11588  }
11589  else if(SpeedTag == 69) // bot sig
11590  {
11591  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11592  {
11593  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11594  {
11595  IAElement = InactiveTrackElementAt(77, IMPair.first);
11596  }
11597  else
11598  {
11599  IAElement = InactiveTrackElementAt(78, IMPair.second);
11600  }
11601  if(IAElement.LocationName == "")
11602  {
11603 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11604  SignalPlatformGraphic = RailGraphics->bm77Striped;
11605  }
11606  else
11607  {
11608 // SignalPlatformGraphic = RailGraphics->Plat69;
11609  SignalPlatformGraphic = RailGraphics->bm77;
11610  }
11611  Utilities->CallLogPop(951);
11612  return(true);
11613  }
11614  }
11615  else if(SpeedTag == 70) // left sig
11616  {
11617  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11618  {
11619  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11620  {
11621  IAElement = InactiveTrackElementAt(55, IMPair.first);
11622  }
11623  else
11624  {
11625  IAElement = InactiveTrackElementAt(82, IMPair.second);
11626  }
11627  if(IAElement.LocationName == "")
11628  {
11629 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11630  SignalPlatformGraphic = RailGraphics->bm78Striped;
11631  }
11632  else
11633  {
11634 // SignalPlatformGraphic = RailGraphics->Plat70;
11635  SignalPlatformGraphic = RailGraphics->bm78;
11636  }
11637  Utilities->CallLogPop(952);
11638  return(true);
11639  }
11640  }
11641  else if(SpeedTag == 71) // right sig
11642  {
11643  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11644  {
11645  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11646  {
11647  IAElement = InactiveTrackElementAt(85, IMPair.first);
11648  }
11649  else
11650  {
11651  IAElement = InactiveTrackElementAt(86, IMPair.second);
11652  }
11653  if(IAElement.LocationName == "")
11654  {
11655 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11656  SignalPlatformGraphic = RailGraphics->gl79Striped;
11657  }
11658  else
11659  {
11660 // SignalPlatformGraphic = RailGraphics->Plat71;
11661  SignalPlatformGraphic = RailGraphics->gl79;
11662  }
11663  Utilities->CallLogPop(953);
11664  return(true);
11665  }
11666  }
11667  Utilities->CallLogPop(954);
11668  return(false);
11669 }
11670 
11671 // ---------------------------------------------------------------------------
11672 
11673 bool TTrack::OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
11674 // returns true if another train on LinkPos track of element at TrackPos, whether bridge or not, return false if not, or if TrackPos == -1,
11675 // or LinkPos == -1, or if only own train on the track. LinkPos can be entry or exit.
11676 {
11677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(TrackPos) + "," +
11678  AnsiString(LinkPos) + "," + AnsiString(OwnTrainID));
11679  if((LinkPos < 0) || (TrackPos < 0))
11680  {
11681  Utilities->CallLogPop(1348);
11682  return(false);
11683  }
11684  TTrackElement TrackElement = TrackElementAt(713, TrackPos);
11685 
11686  if(TrackElement.TrackType != Bridge)
11687  {
11688  Utilities->CallLogPop(1349);
11689  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11690  }
11691 // bridge if reach here
11692  if(LinkPos > 1)
11693  {
11694  Utilities->CallLogPop(1350);
11695  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11696  }
11697  else
11698  {
11699  Utilities->CallLogPop(1351);
11700  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11701  }
11702 }
11703 
11704 // ---------------------------------------------------------------------------
11705 
11707 {
11708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11709  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11710  {
11711  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11712  }
11713  Utilities->CallLogPop(1483);
11714  return(SelectVector.at(At));
11715 }
11716 
11717 // ---------------------------------------------------------------------------
11718 
11719 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11720 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11721 {
11722  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11723  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11724  bool FoundFlag = false;
11725  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11726  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11727 
11728  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11729  Utilities->CallLogPop(1538);
11730  return(FoundFlag);
11731 }
11732 
11733 // ---------------------------------------------------------------------------
11734 
11735 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11736 {
11737 // return true if find an inactive element called 'Name'
11738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11739  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11740  bool FoundFlag = false;
11741 
11742  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11743  {
11744  if(InactiveTrackElementAt(158, x).LocationName == Name)
11745  {
11746  FoundFlag = true;
11747  int V = InactiveTrackElementAt(159, x).VLoc;
11748  int H = InactiveTrackElementAt(160, x).HLoc;
11749  if(V > VLocHi)
11750  {
11751  VLocHi = V;
11752  }
11753  if(V < VLocLo)
11754  {
11755  VLocLo = V;
11756  }
11757  if(H < HLoc)
11758  {
11759  HLoc = H;
11760  }
11761  }
11762  }
11763  if(FoundFlag)
11764  {
11765  VPosHi = 16 * VLocHi;
11766  VPosLo = 16 * VLocLo;
11767  HPos = 16 * HLoc;
11768  Utilities->CallLogPop(1562);
11769  return(true);
11770  }
11771  else
11772  {
11773  Utilities->CallLogPop(1563);
11774  return(false);
11775  }
11776 }
11777 
11778 // ---------------------------------------------------------------------------
11779 
11780 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11781 {
11782 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11783 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11784  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11785  AnsiString(EndTVPosition));
11786  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11787  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11788 
11789 // get H & V values for the element adjacent to Link[0] & Link[1]
11790  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11791  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11792  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11793  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11794 
11795 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11796  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11797  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11798  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11799  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11800 
11801  if(Link0Squares <= Link1Squares)
11802  {
11803  Utilities->CallLogPop(1851);
11804  return(0);
11805  }
11806  else
11807  {
11808  Utilities->CallLogPop(1852);
11809  return(1);
11810  }
11811 }
11812 
11813 // ---------------------------------------------------------------------------
11814 
11815 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11816 {
11817  // element can be points or any other type
11818  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11819  AnsiString(LinkPos));
11820  Derail = false;
11821  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11822 
11823  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11824  {
11825  if(TE.Attribute == 0)
11826  {
11827  Utilities->CallLogPop(663);
11828  return(1); // Att == 0 & ExitPos == 1 represent straight
11829  }
11830  else
11831  {
11832  Utilities->CallLogPop(664);
11833  return(3); // Att == 1 & ExitPos == 3 represent diverging
11834  }
11835  }
11836  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11837  {
11838  if((LinkPos == 1) && (TE.Attribute == 0))
11839  {
11840  Utilities->CallLogPop(665);
11841  return(0); // Att == 0 represents straight
11842  }
11843  else if(LinkPos == 1)
11844  {
11845  Derail = true;
11846  Utilities->CallLogPop(666);
11847  return(0);
11848  }
11849  else if((LinkPos == 3) && (TE.Attribute == 1))
11850  {
11851  Utilities->CallLogPop(667);
11852  return(0);
11853  }
11854  else if(LinkPos == 3)
11855  {
11856  Derail = true;
11857  Utilities->CallLogPop(668);
11858  return(0);
11859  }
11860  }
11861  else if(LinkPos == 0)
11862  {
11863  Utilities->CallLogPop(669);
11864  return(1);
11865  }
11866  else if(LinkPos == 1)
11867  {
11868  Utilities->CallLogPop(670);
11869  return(0);
11870  }
11871  else if(LinkPos == 2)
11872  {
11873  Utilities->CallLogPop(671);
11874  return(3);
11875  }
11876  else if(LinkPos == 3)
11877  {
11878  Utilities->CallLogPop(672);
11879  return(2);
11880  }
11881  throw Exception("Error, failure in GetExitPos"); // should never reach here
11882 }
11883 
11884 // ----------------------------------------------------------------------------
11885 
11887 {
11888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11889  LCVector.clear();
11890  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11891  {
11892  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11893  {
11894  LCVector.push_back(x);
11895  }
11896  }
11897  Utilities->CallLogPop(1931);
11898  return;
11899 }
11900 
11901 // ---------------------------------------------------------------------------
11902 
11903 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11904 /*
11905  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11906  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11907  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11908  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11909 */
11910 {
11911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11912  AnsiString(Link));
11913  bool FoundFlag;
11914 
11915  TrainID = -1;
11916  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11917 
11918  if(!FoundFlag)
11919  {
11920  Utilities->CallLogPop(2001);
11921  return(false);
11922  }
11923  TTrackElement TE = TrackElementAt(882, VecPos);
11924 
11925  TrainID = TE.TrainIDOnElement;
11926  if(TE.TrackType == Bridge)
11927  {
11928  if(TE.TrainIDOnElement > -1)
11929  {
11930  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11931  {
11933  }
11934  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11935  {
11937  }
11938  else
11939  {
11940  TrainID = -1; // shouldn't ever reach here but be safe
11941  }
11942  }
11943  }
11944  if(TrainID == -1)
11945  {
11946  Utilities->CallLogPop(2002);
11947  return(false);
11948  }
11949 // now get the train
11950  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11951 
11952  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11953  {
11954  Utilities->CallLogPop(2003);
11955  return(true);
11956  }
11957  TrainID = -1;
11958  Utilities->CallLogPop(2004);
11959  return(false);
11960 }
11961 
11962 // ---------------------------------------------------------------------------
11963 
11964 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11965 /* New at v1.2.0
11966  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11967  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11968  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11969  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11970  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11971  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11972  Each of these is examined in turn for each route element in the relevant position.
11973 */
11974 {
11975  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11976  "," + AnsiString(DiagonalLinkNumber));
11977  TrainID = -1;
11978  TPrefDirElement TempPrefDirElement;
11979  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11980 
11981  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11982  {
11983  Utilities->CallLogPop(2027);
11984  return(true);
11985  }
11986  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11987  {
11988  Utilities->CallLogPop(2028);
11989  return(true);
11990  }
11991  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11992  {
11993  Utilities->CallLogPop(2029);
11994  return(true);
11995  }
11996  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11997  {
11998  Utilities->CallLogPop(2030);
11999  return(true);
12000  }
12001  Utilities->CallLogPop(2031);
12002  return(false);
12003 }
12004 
12005 // ---------------------------------------------------------------------------
12006 
12007 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12008 {
12009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12010  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12011  TUserGraphicItem UGI;
12012  AnsiString JustFileName = "";
12013 
12014  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12015  {
12016  UGI = UserGraphicVectorAt(17, x);
12017  int LastDelim = UGI.FileName.LastDelimiter('\\');
12018  if(LastDelim == 0) // can't find it so skip this item
12019  {
12020  continue;
12021  }
12022  else
12023  {
12024  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12025  }
12026  Utilities->SaveFileString(VecFile, JustFileName);
12027  Utilities->SaveFileInt(VecFile, UGI.HPos);
12028  Utilities->SaveFileInt(VecFile, UGI.VPos);
12029  }
12030  Utilities->CallLogPop(2178);
12031 }
12032 
12033 // ---------------------------------------------------------------------------
12034 
12035 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12036 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12037 {
12038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12039  int NumPlats = 0;
12040  TTrackElement TempElement;
12041  int TempInt;
12042 
12043  typedef std::list<int> TNamePosList;
12044  TNamePosList NamePosList;
12045  typedef TNamePosList::iterator TNPLIt;
12046  TNPLIt NPLIt;
12047  typedef std::list<int> TOnePlatList;
12048  TOnePlatList OnePlatList;
12049  typedef TOnePlatList::iterator TOPLIt;
12050  TOPLIt OPLIt;
12051 
12052  NamePosList.clear();
12053  OnePlatList.clear();
12054  for(unsigned int x = 0; x < TrackVector.size(); x++)
12055  {
12056  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12057  {
12058  NamePosList.push_back(x);
12059  }
12060  }
12061  //NamePosList complete
12062 
12063  if(!NamePosList.empty()) //first value for the loop examination
12064  {
12065  OnePlatList.push_back(NamePosList.back());
12066  NamePosList.pop_back(); //erase from NPV as done with it here
12067  }
12068  while(!OnePlatList.empty()) //loop to examine all linked elements
12069  {
12070  TempInt = OnePlatList.front();
12071  TempElement = TrackElementAt(989, TempInt);
12072 
12073  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12074  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12075  {
12076  OnePlatList.push_back(TempElement.Conn[0]);
12077  NamePosList.erase(NPLIt);
12078  }
12079  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12080  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12081  {
12082  OnePlatList.push_back(TempElement.Conn[1]);
12083  NamePosList.erase(NPLIt);
12084  }
12085  //here when loaded any connecting links into OnePlatList, so can erase the front element
12086  OnePlatList.erase(OnePlatList.begin());
12087  if(OnePlatList.empty())
12088  {
12089  NumPlats++; //finished with current linked elements so can increment NumPlats
12090  if(!NamePosList.empty())
12091  {
12092  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12093  NamePosList.pop_back(); //erase from NPV as done with it there
12094  }
12095  }
12096  }
12097  Utilities->CallLogPop(2218);
12098  return(NumPlats);
12099 }
12100 
12101 // ---------------------------------------------------------------------------
12102 
12103 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12104 {//repair Signals pointed to by FPVIt
12105  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12106  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12107  if(TE.TrackType != SignalPost)
12108  {
12109  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12110  }
12111  if(!TE.Failed)
12112  {
12113  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12114  }
12115  TE.Failed = false;
12116  //set to correct aspect
12117  int RouteNumber;
12118  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12119  { // 0 for LinkPos ok as a signal so only one track
12120  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12121  }
12122  //erase from vector
12123  Track->FailedSignalsVector.erase(FPVIt);
12124 
12125  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12126  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12127  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12128  AllRoutes->RebuildRailwayFlag = true;
12129  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12130  Utilities->CallLogPop(2519);
12131 }
12132 
12133 // ---------------------------------------------------------------------------
12134 
12135 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12136 {//repair points pointed to by FPVIt
12137  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12138  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12139  if(TE.TrackType != Points)
12140  {
12141  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12142  }
12143  if(!TE.Failed)
12144  {
12145  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12146  }
12147  TE.Failed = false;
12152  //erase from vector
12153  Track->FailedPointsVector.erase(FPVIt);
12154 
12155  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12156  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12157  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12158  AllRoutes->RebuildRailwayFlag = true;
12159  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12160  Utilities->CallLogPop(2518);
12161 }
12162 
12163 // ---------------------------------------------------------------------------
12164 
12165 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12166 {//repair TSR pointed to by FPVIt
12167  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12168  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12169  if(TE.TrackType != Simple)
12170  {
12171  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12172  }
12173  if(!TE.Failed)
12174  {
12175  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12176  }
12177  TE.Failed = false;
12180  //erase from vector
12181  Track->TSRVector.erase(FPVIt);
12182 
12183  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12184  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12185  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12186  AllRoutes->RebuildRailwayFlag = true;
12187  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12188  Utilities->CallLogPop(2520);
12189 }
12190 
12191 // ---------------------------------------------------------------------------
12192 
12194 {
12195  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12196  SimpleVector.clear();
12197  for(unsigned int x = 0; x < TrackVector.size(); x++)
12198  {
12199  if(TrackElementAt(1517, x).TrackType == Simple)
12200  {
12201  SimpleVector.push_back(int(x));
12202  }
12203  }
12204  Utilities->CallLogPop(2521);
12205 }
12206 
12207 // ---------------------------------------------------------------------------
12208 // UserGraphic, PrefDir & Route functions
12209 // ---------------------------------------------------------------------------
12210 
12212 {
12213  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12214  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12215  {
12216  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12217  }
12218  Utilities->CallLogPop(2194);
12219  return(UserGraphicVector.at(At));
12220 }
12221 
12222 // ---------------------------------------------------------------------------
12223 
12224 int TOnePrefDir::LastElementNumber(int Caller) const
12225 {
12226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12227  int RetVal = PrefDirVector.size() - 1;
12228 
12229  if(RetVal < 0)
12230  {
12231  throw Exception("Return value negative in call to LastElementNumber");
12232  }
12233  Utilities->CallLogPop(114);
12234  return(RetVal);
12235 }
12236 
12237 // ---------------------------------------------------------------------------
12239 {
12240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12241  if(PrefDirVector.empty())
12242  {
12243  throw Exception("PrefDirVector empty in call to LastElementPtr");
12244  }
12245  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12246 
12247  Utilities->CallLogPop(115);
12248  return(RetIT);
12249 }
12250 
12251 // ---------------------------------------------------------------------------
12253 {
12254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12255  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12256  {
12257  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12258  }
12259  Utilities->CallLogPop(116);
12260  return(PrefDirVector.at(At));
12261 }
12262 
12263 // ---------------------------------------------------------------------------
12265 {
12266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12267  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12268  {
12269  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12270  " in GetModifiablePrefDirElementAt");
12271  }
12272  Utilities->CallLogPop(117);
12273  return(PrefDirVector.at(At));
12274 }
12275 
12276 // ---------------------------------------------------------------------------
12278 {
12279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12280  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12281  {
12282  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12283  }
12284  Utilities->CallLogPop(118);
12285  return(SearchVector.at(At));
12286 }
12287 
12288 // ---------------------------------------------------------------------------
12290 {
12291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12292  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12293  {
12294  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12295  }
12296  Utilities->CallLogPop(119);
12297  return(SearchVector.at(At));
12298 }
12299 
12300 // ---------------------------------------------------------------------------
12301 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12302 /*
12303  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12304  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12305  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12306  set in later functions.
12307 */
12308 {
12309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12310  ClearPrefDir();
12311  int TrackVectorPosition;
12312  TTrackElement TrackElement;
12313 
12314  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12315  {
12316  Utilities->CallLogPop(126);
12317  return(false);
12318  }
12319 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12320  if(TrackElement.TrackType == Points)
12321  {
12322  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12323  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12324  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12325  //best to prevent it to avoid problems
12326  Utilities->CallLogPop(127);
12327  return false;
12328  }
12329 */
12330  TPrefDirElement PrefDirElement(TrackElement);
12331 
12332  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12333  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12334  StorePrefDirElement(1, PrefDirElement); // enter first element
12335 // Note that ELink not set even if a buffer or continuation - these set in
12336 // ConvertPrefDirSearchVector after 2nd element added
12337 
12338  Utilities->CallLogPop(128);
12339  return(true);
12340 }
12341 
12342 // ---------------------------------------------------------------------------
12343 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12344 
12345 /*
12346  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12347  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12348  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12349  with setting the PrefDir vector, & return true.
12350  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12351  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12352  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12353  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12354  ConvertPrefDirSearchVector to set PrefDirVector.
12355  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12356  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12357  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12358 */
12359 
12360 {
12361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12362  FinishElement = false;
12363  int TrackVectorPosition;
12364 
12365  TotalSearchCount = 0;
12366  TTrackElement TrackElement, TempTrackElement;
12367 
12368  if(PrefDirVector.size() == 0)
12369  {
12370  Utilities->CallLogPop(129);
12371  return(false);
12372  }
12373  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12374  {
12375  Utilities->CallLogPop(130);
12376  return(false);
12377  }
12378 // set the search limits using the last stored element in PrefDirVector as the start point
12379 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12380 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12381 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12382 
12383  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12384 
12385  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12386  {
12387  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12388  SearchLimitHighH = TrackElement.HLoc + 15;
12389  }
12390  else
12391  {
12392  SearchLimitLowH = TrackElement.HLoc - 15;
12393  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12394  }
12395  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12396  {
12397  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12398  SearchLimitHighV = TrackElement.VLoc + 15;
12399  }
12400  else
12401  {
12402  SearchLimitLowV = TrackElement.VLoc - 15;
12403  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12404  }
12405 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12406  check & TotalSearchCounts check
12407  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12408  {
12409  ShowMessage("Unable to reach the selected element - too far ahead");
12410  Utilities->CallLogPop(1692);
12411  return false;
12412  }
12413 */
12414 // get last PrefDir element
12415  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12416  {
12417  // check if TrackElement adjacent to any of the 4 XLinkPos'
12418  for(int x = 0; x < 4; x++)
12419  {
12420  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12421  {
12422  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12423  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12424  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12425  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12426  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12427  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12428  // shouldn't ever get it in a serious railway though.
12429 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12430  }
12431  }
12432  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12433  {
12434  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12435  SearchVector.clear(); // use this & convert to set all PrefDir element values
12436  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12437  {
12439  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12440  {
12441  FinishElement = true;
12442  }
12443  Utilities->CallLogPop(131);
12444  return(true);
12445  }
12446  } // not an adjacent element
12447 
12448  // now check each of the 4 possible XLinkPos values
12449  for(int x = 0; x < 4; x++)
12450  {
12451  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12452  {
12453  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12454  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12455  SearchVector.clear();
12456  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12457  {
12459  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12460  {
12461  FinishElement = true;
12462  }
12463  Utilities->CallLogPop(132);
12464  return(true);
12465  }
12466  }
12467  } // here if checked all possible exits without success
12468  ShowMessage(
12469  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12470  Utilities->CallLogPop(133);
12471  return(false);
12472  }
12473 // dealt above with LastPrefDirElement being the start element (which can be points)
12474 
12475  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12476  .ELinkPos] == Lead)) // leading point
12477  {
12478  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12479  {
12480  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12481  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12482  // can't be buffers or gap if points
12483  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12484  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12485  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12486  SearchVector.clear();
12487  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12488  {
12490  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12491  {
12492  FinishElement = true;
12493  }
12494  Utilities->CallLogPop(134);
12495  return(true);
12496  }
12497  }
12498  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12499  {
12500  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12501  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12502  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12503  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12504  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12505  SearchVector.clear();
12506  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12507  {
12509  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12510  {
12511  FinishElement = true;
12512  }
12513  Utilities->CallLogPop(135);
12514  return(true);
12515  }
12516  }
12517 // above dealt with immediate finds for leading point,
12518 // now deal with ordinary searches for leading point
12519  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12520  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12521  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12522  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12523  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12524  SearchVector.clear();
12525  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12526  {
12528  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12529  {
12530  FinishElement = true;
12531  }
12532  Utilities->CallLogPop(136);
12533  return(true);
12534  }
12535  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12536  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12537  // note that CheckCount already increased to allow for XLinkPos & XLink
12538  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12539  SearchVector.clear();
12540  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12541  {
12543  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12544  {
12545  FinishElement = true;
12546  }
12547  Utilities->CallLogPop(137);
12548  return(true);
12549  }
12550 // here if failed to find match for leading point
12551  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12552  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12553  ShowMessage(
12554  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12555  Utilities->CallLogPop(138);
12556  return(false);
12557  }
12558 // leading point fully dealt with above
12559 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12560 // separately as covered in ordinary search.
12561 
12562  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12563  SearchVector.clear();
12564 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12565  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12566  {
12568  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12569  {
12570  FinishElement = true;
12571  }
12572  Utilities->CallLogPop(139);
12573  return(true);
12574  }
12575  ShowMessage(
12576  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12577  Utilities->CallLogPop(140);
12578  return(false); // failed to find required element
12579 }
12580 
12581 // ---------------------------------------------------------------------------
12582 
12583 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12584 /*
12585  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12586  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12587  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12588  Keep a count of entries in SearchVector during the current function call, so that this number can be
12589  erased for an unproductive branch search.
12590  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12591  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12592  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12593  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12594  If not any of above, store element in searchvector, set the new current element values from the
12595  SearchElement, then go back to the while loop for the next step in the search.
12596 */
12597 {
12598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12599  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12600  int VectorCount = 0;
12601 
12602  while(true)
12603  {
12604  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12605  {
12606  for(int x = 0; x < VectorCount; x++)
12607  {
12608  SearchVector.erase(SearchVector.end() - 1);
12609  }
12610  Utilities->CallLogPop(141);
12611  return(false);
12612  }
12613  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12614  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12615  TPrefDirElement SearchElement(NextTrackElement);
12616  SearchElement.TrackVectorPosition = NextPosition;
12617  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12618  SearchElement.ELinkPos = NextELinkPos;
12619  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12620  int NextXLinkPos;
12621  if(SearchElement.ELinkPos == 0)
12622  {
12623  NextXLinkPos = 1;
12624  }
12625  if(SearchElement.ELinkPos == 1)
12626  {
12627  NextXLinkPos = 0;
12628  }
12629  if(SearchElement.ELinkPos == 2)
12630  {
12631  NextXLinkPos = 3;
12632  }
12633  if(SearchElement.ELinkPos == 3)
12634  {
12635  NextXLinkPos = 2;
12636  }
12637  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12638  {
12639  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12640  // but may be buffers, continuation or gap
12641  SearchElement.XLinkPos = NextXLinkPos;
12642  }
12643 // can't set XLink or XLinkPos yet if the element is a leading point.
12644 // check if found it
12645  if(SearchElement.TrackVectorPosition == RequiredPosition)
12646  {
12647  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12648  VectorCount++; // not really needed but include for tidyness
12649  TotalSearchCount++;
12650  Utilities->CallLogPop(142);
12651  return(true);
12652  }
12653 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12654 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12655 // at a time - drop this
12656 /*
12657  if(PrefDirVector.size() > 200)
12658  {
12659  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12660  Utilities->CallLogPop(1419);
12661  return false;
12662  }
12663 */
12664 // check if a buffer or continuation
12665  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12666  {
12667  for(int x = 0; x < VectorCount; x++)
12668  {
12669  SearchVector.erase(SearchVector.end() - 1);
12670  }
12671  Utilities->CallLogPop(143);
12672  return(false);
12673  }
12674 // check if reached an earlier position on search PrefDir with same entry value
12675  for(unsigned int x = 0; x < SearchVector.size(); x++)
12676  {
12677  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12678  {
12679  for(int x = 0; x < VectorCount; x++)
12680  {
12681  SearchVector.erase(SearchVector.end() - 1);
12682  }
12683  Utilities->CallLogPop(144);
12684  return(false);
12685  }
12686  }
12687 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12688 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12689  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12690  {
12691  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12692  {
12693  for(int x = 0; x < VectorCount; x++)
12694  {
12695  SearchVector.erase(SearchVector.end() - 1);
12696  }
12697  Utilities->CallLogPop(1417);
12698  return(false);
12699  }
12700  }
12701 
12702 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12703 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12704 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12706  {
12707  for(int x = 0; x < VectorCount; x++)
12708  {
12709  SearchVector.erase(SearchVector.end() - 1);
12710  }
12711  Utilities->CallLogPop(1691);
12712  return(false);
12713  }
12714 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12715  if(SearchVector.size() > 150)
12716  {
12717  for(int x = 0; x < VectorCount; x++)
12718  {
12719  SearchVector.erase(SearchVector.end() - 1);
12720  }
12721  Utilities->CallLogPop(1418);
12722  return(false);
12723  }
12724 // check if reached a leading point
12725  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12726  {
12727 // push element with XLink set to position [1]
12728  SearchElement.XLink = SearchElement.Link[1];
12729  SearchElement.XLinkPos = 1;
12730  SearchVector.push_back(SearchElement);
12731  VectorCount++;
12732  TotalSearchCount++;
12733  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12734  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12735  // can't be used. NextTrackElement is the corresponding TTrackElement.
12736  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12737  {
12738  Utilities->CallLogPop(145);
12739  return(true);
12740  }
12741  else
12742  {
12743 // remove leading point with XLinkPos [1]
12744  SearchVector.erase(SearchVector.end() - 1);
12745  VectorCount--;
12746 // push element with XLink set to position [3]
12747  SearchElement.XLink = SearchElement.Link[3];
12748  SearchElement.XLinkPos = 3;
12749  SearchVector.push_back(SearchElement);
12750  VectorCount++;
12751  TotalSearchCount++;
12752 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12753  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12754  {
12755  Utilities->CallLogPop(146);
12756  return(true);
12757  }
12758  else
12759  {
12760  for(int x = 0; x < VectorCount; x++)
12761  {
12762  SearchVector.erase(SearchVector.end() - 1);
12763  }
12764  Utilities->CallLogPop(147);
12765  return(false);
12766  }
12767  }
12768  } // if leading point
12769 
12770 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12771 // ready for next element on PrefDir
12772  SearchVector.push_back(SearchElement);
12773  VectorCount++;
12774  TotalSearchCount++;
12775  XLinkPos = NextXLinkPos;
12776  CurrentTrackElement = SearchElement;
12777  } // while(true)
12778 }
12779 
12780 // ---------------------------------------------------------------------------
12781 
12783 /*
12784  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12785  for each element on the search PrefDir, though if the last element is a leading point
12786  then the final XLink won't be set.
12787  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12788  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12789  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12790 */
12791 {
12792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12793  if(SearchVector.size() == 0)
12794  {
12795  throw Exception("Error, SearchVector empty");
12796  }
12797 // get first SearchElement in order to set last PrefDirelement
12798  TPrefDirElement SearchElement = SearchVector.at(0);
12799 
12800 // set last PrefDir element XLink & ELink values if not already set
12801 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12802  for(int x = 0; x < 4; x++)
12803  {
12804  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12805  {
12806  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12807  {
12808  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12809  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12810  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12811  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12812  }
12813  int ELinkPos;
12814  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12815  {
12816  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12817  }
12818  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12819  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12820  {
12821  ELinkPos = 0;
12822  }
12823  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12824  {
12825  ELinkPos = 3;
12826  }
12827  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12828  {
12829  ELinkPos = 2;
12830  }
12831  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12832  {
12833  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12834  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12835  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12836  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12837  }
12838  break; // no point going any further
12839  }
12840  }
12841 // set EXNumber for last PrefDir element, unless already set
12842 // won't be set if was first element or a leading point
12843  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12844  {
12845 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12846  int EXArray[32][2] = {
12847  {4,6},{2,8}, //horizontal & vertical
12848  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12849  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12850  {1,9},{3,7} //forward & reverse diagonals
12851 */
12852 
12853  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12854  {
12855  throw Exception("Error in EntryExitNumber 1");
12856  }
12857  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12858  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12859  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12860  }
12861 // Last PrefDir element now complete
12862 
12863 // construct remaining PrefDir elements from searchvector
12864  for(unsigned int x = 0; x < SearchVector.size(); x++)
12865  {
12866  SearchElement = SearchVector.at(x);
12867  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12868  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12869  PrefDirElement.ELink = SearchElement.ELink;
12870  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12871  PrefDirElement.XLink = SearchElement.XLink;
12872  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12873 // if XLink & XLinkPos not set don't account for them in CheckCount
12874  if(PrefDirElement.XLink == -1)
12875  {
12876  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12877  }
12878  // & TrackVectorPosition
12879  else
12880  {
12881  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12882  }
12883  // XLink, XLinkPos, TrackVectorPosition
12884 
12885 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12886  if(PrefDirElement.XLink != -1)
12887  {
12888  if(!(PrefDirElement.EntryExitNumber()))
12889  {
12890  throw Exception("Error in EntryExitNumber 2");
12891  }
12892  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12893  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12894  PrefDirElement.CheckCount++;
12895  // all values now incorporated if not a leading point
12896  }
12897 // store PrefDir element
12898  StorePrefDirElement(2, PrefDirElement);
12899  }
12900 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12901  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12902  {
12903  if(ValidatePrefDir(2))
12904  {
12905  ;
12906  } // error messages given within function
12907 
12908  }
12910 /* drop this, check dropped from search
12911  if(PrefDirVector.size() > 200)
12912  {
12913  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12914  }
12915 */
12916  Utilities->CallLogPop(148);
12917 }
12918 
12919 // ---------------------------------------------------------------------------
12920 
12921 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12922 /*
12923  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12924  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12925 */
12926 {
12927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12928  LeadingPoints = false;
12929  if(PrefDirVector.empty())
12930  {
12931  Utilities->CallLogPop(1786);
12932  return(false); // should never be empty but allow for it for safety
12933  }
12934  if(PrefDirVector.size() == 1)
12935  {
12936  Utilities->CallLogPop(149);
12937  return(false); // can't end if only one element
12938  }
12939 /*
12940  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12941  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12942  {
12943  Utilities->CallLogPop(150);
12944  return true;
12945  }
12946 */
12947 // allow for anything but leading points
12948  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12949  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12950  {
12951  Utilities->CallLogPop(1776);
12952  return(true);
12953  }
12954  else
12955  {
12956  LeadingPoints = true;
12957  Utilities->CallLogPop(151);
12958  return(false);
12959  }
12960 }
12961 
12962 // ---------------------------------------------------------------------------
12963 
12965 /*
12966  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12967  and that every element is connected to the next element
12968 */
12969 {
12970  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12971  int Position;
12972  AnsiString ErrorString;
12973  bool Error = false;
12974 
12975  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12976  {
12977  if(PrefDirVector.at(x).HLoc == -2000000000)
12978  {
12979  Error = true;
12980  ErrorString = "HLoc";
12981  Position = x;
12982  }
12983  if(PrefDirVector.at(x).VLoc == -2000000000)
12984  {
12985  Error = true;
12986  ErrorString = "VLoc";
12987  Position = x;
12988  }
12989  if(PrefDirVector.at(x).ELink == -1)
12990  {
12991  Error = true;
12992  ErrorString = "ELink";
12993  Position = x;
12994  }
12995  if(PrefDirVector.at(x).ELinkPos == -1)
12996  {
12997  Error = true;
12998  ErrorString = "ELinkPos";
12999  Position = x;
13000  }
13001  if(PrefDirVector.at(x).XLink == -1)
13002  {
13003  Error = true;
13004  ErrorString = "XLink";
13005  Position = x;
13006  }
13007  if(PrefDirVector.at(x).XLinkPos == -1)
13008  {
13009  Error = true;
13010  ErrorString = "XLinkPos";
13011  Position = x;
13012  }
13013  if(PrefDirVector.at(x).SpeedTag == 0)
13014  {
13015  Error = true;
13016  ErrorString = "Tag";
13017  Position = x;
13018  }
13019  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13020  {
13021  Error = true;
13022  ErrorString = "TrackVectorPosition";
13023  Position = x;
13024  }
13025  if(PrefDirVector.at(x).EXNumber == -1)
13026  {
13027  Error = true;
13028  ErrorString = "EXNumber";
13029  Position = x;
13030  }
13031  if(PrefDirVector.at(x).CheckCount != 9)
13032  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13033  {
13034  Error = true;
13035  ErrorString = "CheckCount";
13036  Position = x;
13037  }
13038 // extra checks
13039  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13040  {
13041  Error = true;
13042  ErrorString = "EntryGraphicPtr";
13043  Position = x;
13044  }
13045  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13046  {
13047  Error = true;
13048  ErrorString = "EntryDirectionGraphicPtr";
13049  Position = x;
13050  }
13051 // end of extra checks
13052  if(x > 0)
13053  {
13054  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13055  {
13056  Error = true;
13057  ErrorString = "Last XLink not connected to this element";
13058  Position = x;
13059  }
13060  }
13061  }
13062  if(Error)
13063  {
13064  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13065  }
13066  else
13067  {
13068  Utilities->CallLogPop(153);
13069  return(true);
13070  }
13071 }
13072 
13073 // ---------------------------------------------------------------------------
13074 
13075 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13076 /*
13077  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13078  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13079  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13080  or a leading point.
13081 */
13082 {
13083  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13084  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13085  {
13086  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13087  {
13088  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13089  {
13090  ErasePrefDirElementAt(1, PrefDirVecPos);
13091  }
13092  if(PrefDirVector.size() == 0)
13093  {
13094  Utilities->CallLogPop(154);
13095  return(true);
13096  }
13097  if(PrefDirVector.size() == 1)
13098  {
13099  PrefDirVector.at(x - 1).ELinkPos = -1;
13100  PrefDirVector.at(x - 1).ELink = -1;
13101  PrefDirVector.at(x - 1).XLinkPos = -1;
13102  PrefDirVector.at(x - 1).XLink = -1;
13103  PrefDirVector.at(x - 1).EXNumber = -1;
13104  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13105  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13106  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13107  Utilities->CallLogPop(155);
13108  return(true);
13109  }
13110  // here with truncate element not first element, so ELink & ELinkPos set
13111  // unset XLink & Pos if a leading point
13112  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13113  {
13114  PrefDirVector.at(x - 1).XLinkPos = -1;
13115  PrefDirVector.at(x - 1).XLink = -1;
13116  PrefDirVector.at(x - 1).EXNumber = -1;
13117  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13118  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13119  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13120  Utilities->CallLogPop(156);
13121  return(true);
13122  }
13123  Utilities->CallLogPop(157);
13124  return(true);
13125  }
13126  }
13127  Utilities->CallLogPop(158);
13128  return(false);
13129 }
13130 
13131 // ---------------------------------------------------------------------------
13132 
13133 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13134 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13135 /*
13136  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13137  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13138  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13139  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13140  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13141  displayed.
13142 */
13143 {
13144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13145  AnsiString((short)BuildingPrefDir));
13146  int HPos, VPos;
13147 
13148  if(PrefDirSize() == 0)
13149  {
13150  Utilities->CallLogPop(159);
13151  return;
13152  }
13153  for(unsigned int x = 0; x < PrefDirSize(); x++)
13154  {
13155  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13156 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13157 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13158 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13159  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13160  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13161  // only the front half of which will be overplotted by the back of the train, then when the train is
13162  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13163  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13164  {
13165  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13166  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13167  {
13168  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13169  }
13170  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13171  // Route, no direction if a single element
13172  {
13173  if(x == 0)
13174  {
13175  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13176  }
13177  if(x == (PrefDirSize() - 1))
13178  {
13179  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13180  }
13181  }
13182  }
13183  }
13184 
13185 // set start & end element colours if building a PrefDir
13186  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13187  {
13188  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13189  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13190  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13191  // set last element colour
13192  if(PrefDirSize() > 1)
13193  {
13194  unsigned int LatestPos = PrefDirSize() - 1;
13195  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13196  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13197  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13198  }
13199  }
13200  Disp->Update();
13201  Utilities->CallLogPop(160);
13202 }
13203 
13204 // ---------------------------------------------------------------------------
13205 
13207 /*
13208  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13209  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13210 */
13211 {
13212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13213  if(PrefDirSize() == 0)
13214  {
13215  Utilities->CallLogPop(1547);
13216  return;
13217  }
13218  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13219  bool FoundFlag;
13221  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13222 
13223  while(MMIT != PrefDir4MultiMap.end())
13224  {
13225  H = MMIT->first.first;
13226  V = MMIT->first.second;
13227  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13228  // always found in order, any missing have PrefDirPosx == -1
13229  if(PrefDirPos0 > -1)
13230  {
13231  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13232  }
13233  if(PrefDirPos1 > -1)
13234  {
13235  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13236  }
13237  if(PrefDirPos2 > -1)
13238  {
13239  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13240  }
13241  if(PrefDirPos3 > -1)
13242  {
13243  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13244  }
13245  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13246  {
13247  // need to plot all 4 in order to obtain all the direction graphics
13248  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13249  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13250  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13251  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13252  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13253  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13254  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13255  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13256  MMIT++;
13257  MMIT++;
13258  MMIT++;
13259  MMIT++;
13260  }
13261  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13262  {
13263  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13264  {
13265  // 0 & 1 constitute the bidirectional PrefDir
13266  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13267  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13268  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13269  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13270  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13271  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13272  MMIT++;
13273  MMIT++;
13274  MMIT++;
13275  }
13276  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13277  {
13278  // 0 & 2 constitute the bidirectional PrefDir
13279  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13280  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13281  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13282  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13283  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13284  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13285  MMIT++;
13286  MMIT++;
13287  MMIT++;
13288  }
13289  else
13290  {
13291  // 1 & 2 constitute the bidirectional PrefDir
13292  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13293  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13294  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13295  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13296  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13297  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13298  MMIT++;
13299  MMIT++;
13300  MMIT++;
13301  }
13302  }
13303  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13304  {
13305  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13306  {
13307  // 0 & 1 constitute the bidirectional PrefDir
13308  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13309  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13310  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13311  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13312  MMIT++;
13313  MMIT++;
13314  }
13315  else
13316  {
13317  // 2 unidirectional PrefDirs
13318  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13319  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13320  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13321  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13322  MMIT++;
13323  MMIT++;
13324  }
13325  }
13326  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13327  {
13328  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13329  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13330  MMIT++;
13331  }
13332  }
13333  Disp->Update();
13334  Utilities->CallLogPop(1548);
13335 }
13336 
13337 // ---------------------------------------------------------------------------
13338 
13339 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13340 {
13341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13342  int TempInt;
13343 
13344  ClearPrefDir();
13345  int NumberOfPrefDirElements = 0;
13346 
13347  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13348  for(int x = 0; x < NumberOfPrefDirElements; x++)
13349  {
13350  VecFile >> TempInt; // TrackVectorPosition
13351  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13352  LoadPrefDirElement.TrackVectorPosition = TempInt;
13353  VecFile >> TempInt;
13354  LoadPrefDirElement.ELink = TempInt;
13355  VecFile >> TempInt;
13356  LoadPrefDirElement.ELinkPos = TempInt;
13357  VecFile >> TempInt;
13358  LoadPrefDirElement.XLink = TempInt;
13359  VecFile >> TempInt;
13360  LoadPrefDirElement.XLinkPos = TempInt;
13361  VecFile >> TempInt;
13362  LoadPrefDirElement.EXNumber = TempInt;
13363  VecFile >> TempInt;
13364  LoadPrefDirElement.CheckCount = TempInt;
13365  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13366  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13367  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13368  if(!(LoadPrefDirElement.IsARoute))
13369  {
13370  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13371  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13372  }
13373  else
13374  {
13375  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13376  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13377  LoadPrefDirElement.PrefDirRoute);
13378  }
13379  StorePrefDirElement(5, LoadPrefDirElement);
13380  Utilities->LoadFileString(VecFile); // marker
13381  }
13383  Utilities->CallLogPop(161);
13384 }
13385 
13386 // ---------------------------------------------------------------------------
13387 
13388 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13389 {
13390  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13391  int TempInt;
13392 
13393  ClearPrefDir();
13394  int NumberOfPrefDirElements = 0;
13395 
13396  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13397  for(int x = 0; x < NumberOfPrefDirElements; x++)
13398  {
13399  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13400  VecFile >> TempInt; // TrackVectorPosition
13401  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13402  LoadPrefDirElement.TrackVectorPosition = TempInt;
13403  VecFile >> TempInt;
13404  LoadPrefDirElement.ELink = TempInt;
13405  VecFile >> TempInt;
13406  LoadPrefDirElement.ELinkPos = TempInt;
13407  VecFile >> TempInt;
13408  LoadPrefDirElement.XLink = TempInt;
13409  VecFile >> TempInt;
13410  LoadPrefDirElement.XLinkPos = TempInt;
13411  VecFile >> TempInt;
13412  LoadPrefDirElement.EXNumber = TempInt;
13413  VecFile >> TempInt;
13414  LoadPrefDirElement.CheckCount = TempInt;
13415  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13416  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13417  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13418  if(!(LoadPrefDirElement.IsARoute))
13419  {
13420  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13421  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13422  }
13423  else
13424  {
13425  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13426  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13427  LoadPrefDirElement.PrefDirRoute);
13428  }
13429  StorePrefDirElement(0, LoadPrefDirElement);
13430  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13431  }
13433  Utilities->CallLogPop(1509);
13434 }
13435 
13436 // ---------------------------------------------------------------------------
13437 
13438 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13439 /*
13440  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13441  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13442 */
13443 {
13444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13445  int TempInt;
13446  int NumberOfPrefDirElements = 0;
13447 
13448  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13449  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13450  {
13451  Utilities->CallLogPop(1152);
13452  return(false);
13453  }
13454  for(int x = 0; x < NumberOfPrefDirElements; x++)
13455  {
13456  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13457  {
13458  Utilities->CallLogPop(1766);
13459  return(false);
13460  }
13461  VecFile >> TempInt;
13462  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13463  {
13464  Utilities->CallLogPop(163);
13465  return(false);
13466  }
13467  VecFile >> TempInt;
13468  if((TempInt < -1) || (TempInt > 9)) // ELink
13469  {
13470  Utilities->CallLogPop(162);
13471  return(false);
13472  }
13473  VecFile >> TempInt;
13474  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13475  {
13476  Utilities->CallLogPop(164);
13477  return(false);
13478  }
13479  VecFile >> TempInt;
13480  if((TempInt < -1) || (TempInt > 9)) // XLink
13481  {
13482  Utilities->CallLogPop(165);
13483  return(false);
13484  }
13485  VecFile >> TempInt;
13486  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13487  {
13488  Utilities->CallLogPop(166);
13489  return(false);
13490  }
13491  VecFile >> TempInt;
13492  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13493  {
13494  Utilities->CallLogPop(167);
13495  return(false);
13496  }
13497  VecFile >> TempInt;
13498  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13499  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13500  // ELinkPos, XLink, XLinkPos & EXNumber
13501  {
13502  Utilities->CallLogPop(168);
13503  return(false);
13504  }
13505  VecFile >> TempInt;
13506  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13507  {
13508  Utilities->CallLogPop(1147);
13509  return(false);
13510  }
13511  VecFile >> TempInt;
13512  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13513  {
13514  Utilities->CallLogPop(1510);
13515  return(false);
13516  }
13517  VecFile >> TempInt;
13518  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13519  {
13520  Utilities->CallLogPop(1148);
13521  return(false);
13522  }
13523  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13524  {
13525  Utilities->CallLogPop(1700);
13526  return(false);
13527  }
13528  }
13529  Utilities->CallLogPop(169);
13530  return(true);
13531 }
13532 
13533 // ---------------------------------------------------------------------------
13534 
13535 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13536 {
13537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13538  int NumberOfPrefDirElements = PrefDirVector.size();
13539 
13540  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13541  for(int y = 0; y < NumberOfPrefDirElements; y++)
13542  {
13543  VecFile << y << '\n'; // extra
13544  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13545  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13546  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13547  VecFile << PrefDirVector.at(y).XLink << '\n';
13548  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13549  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13550  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13551  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13552  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13553  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13554  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13555  {
13556  VecFile << "************" << '\0' << '\n'; // marker
13557  }
13558  else
13559  {
13560  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13561  }
13562  }
13563  Utilities->CallLogPop(170);
13564 }
13565 
13566 // ---------------------------------------------------------------------------
13567 
13568 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13569 {
13570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13571  int NumberOfSearchElements = SearchVector.size();
13572 
13573  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13574  for(int y = 0; y < NumberOfSearchElements; y++)
13575  {
13576  VecFile << y << '\n'; // extra
13577  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13578  VecFile << SearchVector.at(y).ELink << '\n';
13579  VecFile << SearchVector.at(y).ELinkPos << '\n';
13580  VecFile << SearchVector.at(y).XLink << '\n';
13581  VecFile << SearchVector.at(y).XLinkPos << '\n';
13582  VecFile << SearchVector.at(y).EXNumber << '\n';
13583  VecFile << SearchVector.at(y).CheckCount << '\n';
13584  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13585  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13586  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13587  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13588  {
13589  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13590  }
13591  else
13592  {
13593  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13594  }
13595  }
13596  Utilities->CallLogPop(1847);
13597 }
13598 
13599 // ---------------------------------------------------------------------------
13600 
13601 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13602 /*
13603  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13604  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13605 */
13606 {
13607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13608  AnsiString(VLoc));
13609  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13610 
13611  if(VecPos > -1)
13612  {
13613  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13614  }
13615  else
13616  {
13617  Utilities->CallLogPop(171);
13618  return;
13619  }
13620  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13621  if(VecPos > -1)
13622  {
13623  ErasePrefDirElementAt(3, VecPos);
13624  }
13625  else
13626  {
13627  Utilities->CallLogPop(172);
13628  return;
13629  }
13630  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13631  if(VecPos > -1)
13632  {
13633  ErasePrefDirElementAt(4, VecPos);
13634  }
13635  else
13636  {
13637  Utilities->CallLogPop(173);
13638  return;
13639  }
13640  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13641  if(VecPos > -1)
13642  {
13643  ErasePrefDirElementAt(5, VecPos);
13644  }
13645  else
13646  {
13647  Utilities->CallLogPop(174);
13648  return;
13649  }
13650  Utilities->CallLogPop(175);
13651 }
13652 
13653 // ---------------------------------------------------------------------------
13654 /*
13655  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13656  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13657 
13658  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13659  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13660  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13661  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13662  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13663  PrefDirVector to correspond to the new track layout.
13664 
13665  {
13666  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13667  if(PrefDirSize() == 0)
13668  {
13669  Utilities->CallLogPop(176);
13670  return;
13671  }
13672  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13673  {
13674  int TV = PrefDirVector.at(x).TrackVectorPosition;
13675  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13676  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13677  if(Track->BlankElementAt(0, TV))
13678  {
13679  ErasePrefDirElementAt(6, x);
13680  }
13681  //if was a blankelement at x then ConnELink and ConnXLink both -1
13682  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13683  {
13684  ErasePrefDirElementAt(7, x);
13685  }
13686  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13687  //needs to be erased once, but if don't use 'else' then will erase two elements
13688  //since 'x' will correspond to the element after the first erased element
13689  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13690  {
13691  ErasePrefDirElementAt(8, x);
13692  }
13693  }
13694  Utilities->CallLogPop(177);
13695  }
13696 */
13697 // ---------------------------------------------------------------------------
13698 
13699 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13700 /*
13701  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13702  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13703 */
13704 {
13705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13706  bool AlreadyPresent, FoundFlag;
13707  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13708 
13709  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13710  {
13711  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13712  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13713  AlreadyPresent = false;
13714  if(FoundFlag)
13715  {
13716  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13717  {
13718  AlreadyPresent = true;
13719  }
13720  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13721  {
13722  AlreadyPresent = true;
13723  }
13724  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13725  {
13726  AlreadyPresent = true;
13727  }
13728  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13729  {
13730  AlreadyPresent = true;
13731  }
13732  }
13733  if(!AlreadyPresent)
13734  {
13735  StorePrefDirElement(4, TempElement);
13736  }
13737  }
13739  Utilities->CallLogPop(178);
13740 }
13741 /* earlier brute force search
13742  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13743  {
13744  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13745  bool AlreadyPresent = false;
13746  for(unsigned int y = 0;y<PrefDirSize();y++)
13747  {
13748  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13749  }
13750  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13751  }
13752 */
13753 
13754 // ---------------------------------------------------------------------------
13755 
13757 /*
13758  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13759  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13760  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13761  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13762  positions are likely to have changed, so this function is called to reset all the necessary connections and
13763  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13764  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13765  shouldn't have changed.
13766 */
13767 {
13768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13769  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13770  {
13771  bool FoundFlag;
13772  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13773  if(FoundFlag)
13774  {
13775  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13776  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13777  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13778  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13779  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13780  for(unsigned int z = 0; z < 4; z++)
13781  {
13782  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13783  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13784  }
13785  }
13786  else
13787  {
13788  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13789  }
13790  }
13791  Utilities->CallLogPop(179);
13792 }
13793 
13794 // ---------------------------------------------------------------------------
13795 
13797 /*
13798  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13799 */
13800 {
13801  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13802  bool DiscrepancyFound = false;
13803 
13804  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13805  {
13806  bool FoundFlag;
13807  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13808  if(FoundFlag)
13809  {
13810  TPrefDirElement PE = PrefDirVector.at(x);
13811  if(PE.TrackVectorPosition != VecPos)
13812  {
13813  DiscrepancyFound = true;
13814  break;
13815  }
13816  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13817  {
13818  DiscrepancyFound = true;
13819  break;
13820  }
13821  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13822  {
13823  DiscrepancyFound = true;
13824  break;
13825  }
13826  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13827  {
13828  DiscrepancyFound = true;
13829  break;
13830  }
13831  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13832  {
13833  DiscrepancyFound = true;
13834  break;
13835  }
13836  }
13837  else
13838  {
13839  DiscrepancyFound = true;
13840  }
13841  }
13842  if(DiscrepancyFound)
13843  {
13844  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13845  ClearPrefDir(); // also clears multimap
13846  }
13847  Utilities->CallLogPop(1436);
13848 }
13849 
13850 // ---------------------------------------------------------------------------
13851 
13853 /*
13854  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13855  return true for OK
13856 */
13857 {
13858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13859  bool DiscrepancyFound = false;
13860 
13861  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13862  {
13863  bool FoundFlag;
13864  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13865  if(FoundFlag)
13866  {
13867  TPrefDirElement PE = PrefDirVector.at(x);
13868  if(PE.TrackVectorPosition != VecPos)
13869  {
13870  DiscrepancyFound = true;
13871  }
13872  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13873  {
13874  DiscrepancyFound = true;
13875  break;
13876  }
13877  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13878  {
13879  DiscrepancyFound = true;
13880  break;
13881  }
13882  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13883  {
13884  DiscrepancyFound = true;
13885  break;
13886  }
13887  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13888  {
13889  DiscrepancyFound = true;
13890  break;
13891  }
13892  }
13893  else
13894  {
13895  DiscrepancyFound = true;
13896  }
13897  }
13898  Utilities->CallLogPop(1512);
13899  return(!DiscrepancyFound);
13900 }
13901 
13902 // ---------------------------------------------------------------------------
13903 
13904 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13905 /*
13906  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13907  turn and for the overall sizes.
13908 */
13909 {
13910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13911  bool FoundFlag = false;
13912  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13913 
13914  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13915  {
13916  TPrefDirElement CheckElement = PrefDirVector.at(a);
13917  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13918  if(!FoundFlag)
13919  {
13920  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13921  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13922  }
13923  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13924  {
13925  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13926  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13927  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13928  }
13929  }
13930  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13931  {
13932  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13933  + " Caller=" + (AnsiString)Caller);
13934  }
13935  Utilities->CallLogPop(180);
13936 }
13937 
13938 // ---------------------------------------------------------------------------
13939 
13940 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13941  int &PrefDirPos3)
13942 /*
13943  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13944  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13945  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13946  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13947  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13948 */
13949 {
13950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13951  AnsiString(VLoc));
13952  THVPair PrefDirMapKeyPair;
13953 
13954  PrefDirPos0 = -1;
13955  PrefDirPos1 = -1;
13956  PrefDirPos2 = -1;
13957  PrefDirPos3 = -1;
13958  FoundFlag = false;
13959  PrefDirMapKeyPair.first = HLoc;
13960  PrefDirMapKeyPair.second = VLoc;
13961  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13962 
13963  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13964  if(ItPair.first == ItPair.second) //none found
13965  {
13966  Utilities->CallLogPop(181);
13967  return;
13968  }
13969  else
13970  {
13971  FoundFlag = true;
13972  PrefDirPos0 = ItPair.first->second;
13973  ItPair.first++;
13974  if(ItPair.first == ItPair.second)
13975  {
13976  Utilities->CallLogPop(182); //only one found
13977  return;
13978  }
13979  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13980  {
13981  PrefDirPos1 = ItPair.first->second;
13982  }
13983  ItPair.first++;
13984  if(ItPair.first == ItPair.second)
13985  {
13986  Utilities->CallLogPop(183); //2 found
13987  return;
13988  }
13989  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13990  {
13991  PrefDirPos2 = ItPair.first->second;
13992  }
13993  ItPair.first++;
13994  if(ItPair.first == ItPair.second)
13995  {
13996  Utilities->CallLogPop(184); //3 found
13997  return;
13998  }
13999  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14000  {
14001  PrefDirPos3 = ItPair.first->second; //4 found
14002  }
14003  }
14004  Utilities->CallLogPop(185);
14005 }
14006 
14007 // ---------------------------------------------------------------------------
14008 
14009 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14010 { //not used after modified the pref dir checking function at v2.13.0
14011  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14012  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14013  try
14014  {
14015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14016  + "," + AnsiString(LinkNumberPos));
14017  bool FoundFlag;
14018  int PD0, PD1, PD2, PD3;
14019  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14020  {
14021  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14022  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14023  PD0, PD1, PD2, PD3);
14024  if(!FoundFlag)
14025  {
14026  Utilities->CallLogPop(2282);
14027  return(false);
14028  }
14029  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14030  {
14031  if(PD0 > -1)
14032  {
14033  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14034  {
14035  LinkedPrefDirVectorNumber = PD0;
14036  Utilities->CallLogPop(2283);
14037  return(true);
14038  }
14039  }
14040  if(PD1 > -1)
14041  {
14042  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14043  {
14044  LinkedPrefDirVectorNumber = PD1;
14045  Utilities->CallLogPop(2284);
14046  return(true);
14047  }
14048  }
14049  }
14050  if(PD0 > -1)
14051  {
14052  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14053  {
14054  LinkedPrefDirVectorNumber = PD0;
14055  Utilities->CallLogPop(2285);
14056  return(true);
14057  }
14058  }
14059  if(PD1 > -1)
14060  {
14061  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14062  {
14063  LinkedPrefDirVectorNumber = PD1;
14064  Utilities->CallLogPop(2286);
14065  return(true);
14066  }
14067  }
14068  if(PD2 > -1)
14069  {
14070  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14071  {
14072  LinkedPrefDirVectorNumber = PD2;
14073  Utilities->CallLogPop(2287);
14074  return(true);
14075  }
14076  }
14077  if(PD3 > -1)
14078  {
14079  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14080  {
14081  LinkedPrefDirVectorNumber = PD3;
14082  Utilities->CallLogPop(2288);
14083  return(true);
14084  }
14085  }
14086  LinkedPrefDirVectorNumber = -1;
14087  Utilities->CallLogPop(2289);
14088  return(false);
14089  }
14090  else //buffer or continuation, no link at position 0 but not a failure
14091  {
14092  LinkedPrefDirVectorNumber = -1;
14093  Utilities->CallLogPop(2290);
14094  return(true);
14095  }
14096  }
14097  catch(const Exception &e) //non error catch
14098  {
14099  LinkedPrefDirVectorNumber = -1;
14100  Utilities->CallLogPop(2291);
14101  return(false);
14102  }
14103 }
14104 
14105 // ---------------------------------------------------------------------------
14106 
14107 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14108 { //not used after modified the pref dir checking function at v2.13.0
14109  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14110  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14111  try
14112  {
14113  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14114  + "," + AnsiString(LinkNumberPos));
14115  bool FoundFlag;
14116  int PD0, PD1, PD2, PD3;
14117  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14118  {
14119  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14120  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14121  PD0, PD1, PD2, PD3);
14122  if(!FoundFlag)
14123  {
14124  Utilities->CallLogPop(2468);
14125  return(false);
14126  }
14127  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14128  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14129  if(PD0 > -1)
14130  {
14131  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14132  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14133  {
14134  LinkedPrefDirVectorNumber = PD0;
14135  Utilities->CallLogPop(2469);
14136  return(true);
14137  }
14138  }
14139  if(PD1 > -1)
14140  {
14141  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14142  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14143  {
14144  LinkedPrefDirVectorNumber = PD1;
14145  Utilities->CallLogPop(2470);
14146  return(true);
14147  }
14148  }
14149  LinkedPrefDirVectorNumber = -1;
14150  Utilities->CallLogPop(2471);
14151  return(false);
14152  }
14153  if(PD0 > -1)
14154  {
14155  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14156  {
14157  LinkedPrefDirVectorNumber = PD0;
14158  Utilities->CallLogPop(2472);
14159  return(true);
14160  }
14161  }
14162  if(PD1 > -1)
14163  {
14164  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14165  {
14166  LinkedPrefDirVectorNumber = PD1;
14167  Utilities->CallLogPop(2473);
14168  return(true);
14169  }
14170  }
14171  if(PD2 > -1)
14172  {
14173  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14174  {
14175  LinkedPrefDirVectorNumber = PD2;
14176  Utilities->CallLogPop(2474);
14177  return(true);
14178  }
14179  }
14180  if(PD3 > -1)
14181  {
14182  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14183  {
14184  LinkedPrefDirVectorNumber = PD3;
14185  Utilities->CallLogPop(2475);
14186  return(true);
14187  }
14188  }
14189  LinkedPrefDirVectorNumber = -1;
14190  Utilities->CallLogPop(2476);
14191  return(false);
14192  }
14193  else //buffer or continuation, no link at position 0 but not a failure
14194  {
14195  LinkedPrefDirVectorNumber = -1;
14196  Utilities->CallLogPop(2477);
14197  return(true);
14198  }
14199  }
14200  catch(const Exception &e) //non error catch
14201  {
14202  LinkedPrefDirVectorNumber = -1;
14203  Utilities->CallLogPop(2478);
14204  return(false);
14205  }
14206 }
14207 
14208 // ---------------------------------------------------------------------------
14209 
14211 {
14212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14213  bool FoundFlag; //not used
14214  int PD0, PD1, PD2, PD3;
14215  //recover all PDs at the H & V of PDPtr
14216  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14217 
14218  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14219  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14220 
14221  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14222  {
14223  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14224  {
14225  Utilities->CallLogPop(2292);
14226  return(true);
14227  }
14228  }
14229  if(PD1 > -1)
14230  {
14231  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14232  {
14233  Utilities->CallLogPop(2293);
14234  return(true);
14235  }
14236  }
14237  if(PD2 > -1)
14238  {
14239  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14240  {
14241  Utilities->CallLogPop(2294);
14242  return(true);
14243  }
14244  }
14245  if(PD3 > -1)
14246  {
14247  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14248  {
14249  Utilities->CallLogPop(2295);
14250  return(true);
14251  }
14252  }
14253  Utilities->CallLogPop(2296);
14254  return(false);
14255 }
14256 
14257 // ---------------------------------------------------------------------------
14258 
14259 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14260 /*
14261  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14262 */
14263 {
14264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14265  PrefDirVector.push_back(LoadPrefDirElement);
14266  THVPair PrefDir4MultiMapKeyPair;
14267  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14268 
14269  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14270  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14271  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14272  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14273  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14274 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14275  Utilities->CallLogPop(186);
14276 }
14277 
14278 // ---------------------------------------------------------------------------
14279 
14280 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14281 /*
14282  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14283  4MultiMap if they are greater than the erased value.
14284 */
14285 {
14286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14287  bool FoundFlag;
14288 
14289  if(!PrefDirVector.empty())
14290  {
14291  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14292  if(!FoundFlag)
14293  {
14294  throw Exception("Failed to find PrefDir4MultiMap erase element");
14295  }
14296  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14297  PrefDir4MultiMap.erase(EraseIt);
14298  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14300  }
14301  Utilities->CallLogPop(187);
14302 }
14303 
14304 // ---------------------------------------------------------------------------
14305 
14306 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14307 /*
14308  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14309  4MultiMap if they are greater than the erased value.
14310 */
14311 {
14312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14313  AnsiString(ErasedElementNumber));
14314  if(!PrefDir4MultiMap.empty())
14315  {
14316  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14317  {
14318  if(MapPtr->second > ErasedElementNumber)
14319  {
14320  MapPtr->second--;
14321  }
14322  }
14323  }
14324  Utilities->CallLogPop(1450);
14325 }
14326 
14327 // ---------------------------------------------------------------------------
14328 
14329 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14330 /*
14331  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14332  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14333  nothing is found this is an error but the error message is given in the calling function.
14334 */
14335 {
14336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14337  FoundFlag = false;
14338  if(PrefDirVectorPosition >= PrefDirVector.size())
14339  {
14340  throw Exception("PrefDirVectorPosition out of range");
14341  }
14342  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14343  THVPair PrefDir4MultiMapKeyPair;
14344 
14345  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14346  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14347  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14348 
14349  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14350  if(ItPair.first == ItPair.second)
14351  {
14352  Utilities->CallLogPop(188);
14353  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14354  }
14355  else
14356  {
14357  if(ItPair.first->second == PrefDirVectorPosition)
14358  {
14359  FoundFlag = true;
14360  Utilities->CallLogPop(189);
14361  return(ItPair.first);
14362  }
14363  ItPair.first++;
14364  if(ItPair.first == ItPair.second)
14365  {
14366  Utilities->CallLogPop(190);
14367  return(ItPair.first); // nothing found
14368  }
14369  if(ItPair.first->second == PrefDirVectorPosition)
14370  {
14371  FoundFlag = true;
14372  Utilities->CallLogPop(191);
14373  return(ItPair.first);
14374  }
14375  ItPair.first++;
14376  if(ItPair.first == ItPair.second)
14377  {
14378  Utilities->CallLogPop(192);
14379  return(ItPair.first); // nothing found
14380  }
14381  if(ItPair.first->second == PrefDirVectorPosition)
14382  {
14383  FoundFlag = true;
14384  Utilities->CallLogPop(193);
14385  return(ItPair.first);
14386  }
14387  ItPair.first++;
14388  if(ItPair.first == ItPair.second)
14389  {
14390  Utilities->CallLogPop(194);
14391  return(ItPair.first); // nothing found
14392  }
14393  if(ItPair.first->second == PrefDirVectorPosition)
14394  {
14395  FoundFlag = true;
14396  Utilities->CallLogPop(195);
14397  return(ItPair.first);
14398  }
14399  }
14400  Utilities->CallLogPop(196);
14401  return(ItPair.first); // nothing found
14402 }
14403 
14404 // ---------------------------------------------------------------------------
14405 
14406 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14407 /*
14408  Although there may be up to four entries at one H & V position this function gets just one. It is
14409  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14410  at H & V.
14411 */
14412 {
14413  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14414  THVPair PrefDir4MultiMapKeyPair;
14415 
14416  PrefDir4MultiMapKeyPair.first = HLoc;
14417  PrefDir4MultiMapKeyPair.second = VLoc;
14418  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14419 
14420  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14421  if(ItPair.first == ItPair.second) // nothing found
14422  {
14423  Utilities->CallLogPop(197);
14424  return(-1);
14425  }
14426  else
14427  {
14428  Utilities->CallLogPop(198);
14429  return(ItPair.first->second);
14430  }
14431 }
14432 
14433 // ---------------------------------------------------------------------------
14434 
14435 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14436 {
14437  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14438  bool ErasedFlag = false;
14439 
14440  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14441  {
14442  if(PrefDirSize() == 0)
14443  {
14444  Utilities->CallLogPop(1511);
14445  return;
14446  }
14447  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14448  {
14449  ErasedFlag = false;
14450  // use 'else' to ensure don't try to access an erased element
14451  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14452  {
14453  ErasePrefDirElementAt(11, x);
14454  ErasedFlag = true;
14455  }
14456  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14457  {
14458  ErasePrefDirElementAt(12, x);
14459  ErasedFlag = true;
14460  }
14461  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14462  {
14463  ErasePrefDirElementAt(13, x);
14464  ErasedFlag = true;
14465  }
14466  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14467  {
14468  ErasePrefDirElementAt(9, x);
14469  ErasedFlag = true;
14470  }
14471  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14472  {
14473  ErasePrefDirElementAt(10, x);
14474  ErasedFlag = true;
14475  }
14476  if(!ErasedFlag)
14477  {
14478  // don't use 'else' here as may be more than one that need decrementing
14479  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14480  {
14481  PrefDirVector.at(x).TrackVectorPosition--;
14482  }
14483  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14484  {
14485  PrefDirVector.at(x).Conn[0]--;
14486  }
14487  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14488  {
14489  PrefDirVector.at(x).Conn[1]--;
14490  }
14491  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14492  {
14493  PrefDirVector.at(x).Conn[2]--;
14494  }
14495  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14496  {
14497  PrefDirVector.at(x).Conn[3]--;
14498  }
14499  }
14500  }
14501  }
14502  Utilities->CallLogPop(1434);
14503 }
14504 
14505 // ---------------------------------------------------------------------------
14506 
14507 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14508 {
14509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14510  OverallDistance = 0;
14511  OverallSpeedLimit = 0;
14512  LeadingPointsAtLastElement = false;
14513  if(PrefDirSize() == 0) // shouldn't be empty when this called
14514  {
14515  Utilities->CallLogPop(1491);
14516  return;
14517  }
14518  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14519  {
14520  LeadingPointsAtLastElement = true;
14521  Utilities->CallLogPop(1492);
14522  return;
14523  }
14524  for(unsigned int x = 0; x < PrefDirSize(); x++)
14525  {
14526  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14527  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14528  {
14529  OverallDistance += PrefDirElement.Length23;
14530  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14531  {
14532  if(x == 0)
14533  {
14534  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14535  }
14536  else
14537  {
14538  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14539  {
14540  OverallSpeedLimit = -1;
14541  }
14542  }
14543  }
14544  }
14545  else
14546  {
14547  OverallDistance += PrefDirElement.Length01;
14548  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14549  {
14550  if(x == 0)
14551  {
14552  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14553  }
14554  else
14555  {
14556  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14557  {
14558  OverallSpeedLimit = -1;
14559  }
14560  }
14561  }
14562  }
14563  }
14564  Utilities->CallLogPop(1529);
14565 }
14566 
14567 // ---------------------------------------------------------------------------
14568 
14569 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14570 {
14571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14572  if(PrefDirSize() == 0)
14573  {
14574  Utilities->CallLogPop(1564);
14575  return;
14576  }
14577  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14578  bool FoundFlag;
14580  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14581 
14582  while(MMIT != PrefDir4MultiMap.end())
14583  {
14584  HLoc = MMIT->first.first;
14585  VLoc = MMIT->first.second;
14586  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14587  H = HLoc - Track->GetHLocMin();
14588  V = VLoc - Track->GetVLocMin();
14589  // always found in order, any missing have PrefDirPosx == -1
14590  if(PrefDirPos0 > -1)
14591  {
14592  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14593  }
14594  if(PrefDirPos1 > -1)
14595  {
14596  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14597  }
14598  if(PrefDirPos2 > -1)
14599  {
14600  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14601  }
14602  if(PrefDirPos3 > -1)
14603  {
14604  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14605  }
14606  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14607  {
14608  // need to plot all 4 in order to obtain all the direction graphics
14609  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14610  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14611  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14612  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14613  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14614  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14615  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14616  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14617  MMIT++;
14618  MMIT++;
14619  MMIT++;
14620  MMIT++;
14621  }
14622  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14623  {
14624  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14625  {
14626  // 0 & 1 constitute the bidirectional PrefDir
14627  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14628  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14629  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14630  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14631  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14632  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14633  MMIT++;
14634  MMIT++;
14635  MMIT++;
14636  }
14637  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14638  {
14639  // 0 & 2 constitute the bidirectional PrefDir
14640  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14641  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14642  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14643  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14644  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14645  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14646  MMIT++;
14647  MMIT++;
14648  MMIT++;
14649  }
14650  else
14651  {
14652  // 1 & 2 constitute the bidirectional PrefDir
14653  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14654  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14655  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14656  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14657  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14658  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14659  MMIT++;
14660  MMIT++;
14661  MMIT++;
14662  }
14663  }
14664  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14665  {
14666  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14667  {
14668  // 0 & 1 constitute the bidirectional PrefDir
14669  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14670  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14671  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14672  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14673  MMIT++;
14674  MMIT++;
14675  }
14676  else
14677  {
14678  // 2 unidirectional PrefDirs
14679  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14680  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14681  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14682  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14683  MMIT++;
14684  MMIT++;
14685  }
14686  }
14687  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14688  {
14689  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14690  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14691  MMIT++;
14692  }
14693  }
14694  Utilities->CallLogPop(1565);
14695 }
14696 
14697 // ---------------------------------------------------------------------------
14698 
14699 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14700 /*
14701  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14702  level crossing, signals with wrong direction set, or buffers.
14703 */
14704 {
14705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14706  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14707  bool FoundFlag;
14709  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14710 
14711  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14712  ElementIn.VLoc)))
14713  {
14714  Utilities->CallLogPop(1982);
14715  return(false);
14716  }
14717  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14718  {
14719  Utilities->CallLogPop(1983);
14720  return(false);
14721  }
14722 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14723  {
14724  Utilities->CallLogPop(1995);
14725  return(false);
14726  }
14727 */
14728 // Now check that there is only a single prefdir set
14729  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14730 // always found in order, any missing have PrefDirPosx == -1
14731  if(PrefDirPos0 > -1)
14732  {
14733  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14734  }
14735  if(PrefDirPos1 > -1)
14736  {
14737  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14738  }
14739  if(PrefDirPos2 > -1)
14740  {
14741  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14742  }
14743  if(PrefDirPos3 > -1)
14744  {
14745  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14746  }
14747  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14748  {
14749  Utilities->CallLogPop(1984);
14750  return(false);
14751  }
14752  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14753  {
14754  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14755  {
14756  Utilities->CallLogPop(1985);
14757  return(false);
14758  }
14759  else
14760  {
14761  Utilities->CallLogPop(1986);
14762  return(true);
14763  }
14764  }
14765  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14766  {
14767  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14768  {
14769  Utilities->CallLogPop(1987);
14770  return(false);
14771  }
14772  else
14773  {
14774  Utilities->CallLogPop(1988);
14775  return(true);
14776  }
14777  }
14778  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14779  {
14780  if(PrefDirElement0.XLinkPos == EntryPos)
14781  {
14782  Utilities->CallLogPop(1989);
14783  return(false);
14784  }
14785  else
14786  {
14787  Utilities->CallLogPop(1990);
14788  return(true);
14789  }
14790  }
14791  else
14792  {
14793  Utilities->CallLogPop(1991);
14794  return(false); // none found
14795  }
14796 }
14797 
14798 // ---------------------------------------------------------------------------
14799 
14801 {
14802 /* //Added at v2.1.0
14803  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14804  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14805  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14806  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14807  and can be modelled better anyway.
14808 
14809  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14810  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14811  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14812  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14813  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14814  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14815 */
14816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14817  ElementIn.VLoc + "," + XLink);
14818  int TrackVecPos;
14819  bool TrackFoundFlag;
14820  TTrackElement TempTrackElement;
14821 
14822  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14823  {
14824  Utilities->CallLogPop(2047);
14825  return(false);
14826  }
14827 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14828  if(XLink == 1)
14829  {
14830  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14831  if(TrackFoundFlag)
14832  {
14833  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14834  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14835  {
14836  Utilities->CallLogPop(2048);
14837  return(true);
14838  }
14839  }
14840  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14841  if(TrackFoundFlag)
14842  {
14843  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14844  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14845  {
14846  Utilities->CallLogPop(2049);
14847  return(true);
14848  }
14849  }
14850  }
14851 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14852  if(XLink == 3)
14853  {
14854  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14855  if(TrackFoundFlag)
14856  {
14857  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14858  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14859  {
14860  Utilities->CallLogPop(2050);
14861  return(true);
14862  }
14863  }
14864  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14865  if(TrackFoundFlag)
14866  {
14867  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14868  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14869  {
14870  Utilities->CallLogPop(2051);
14871  return(true);
14872  }
14873  }
14874  }
14875 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14876  if(XLink == 7)
14877  {
14878  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14879  if(TrackFoundFlag)
14880  {
14881  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14882  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14883  {
14884  Utilities->CallLogPop(2052);
14885  return(true);
14886  }
14887  }
14888  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14889  if(TrackFoundFlag)
14890  {
14891  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14892  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14893  {
14894  Utilities->CallLogPop(2053);
14895  return(true);
14896  }
14897  }
14898  }
14899 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14900  if(XLink == 9)
14901  {
14902  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14903  if(TrackFoundFlag)
14904  {
14905  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14906  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14907  {
14908  Utilities->CallLogPop(2054);
14909  return(true);
14910  }
14911  }
14912  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14913  if(TrackFoundFlag)
14914  {
14915  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14916  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14917  {
14918  Utilities->CallLogPop(2055);
14919  return(true);
14920  }
14921  }
14922  }
14923  Utilities->CallLogPop(2056);
14924  return(false);
14925 }
14926 
14927 // ---------------------------------------------------------------------------
14928 
14929 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14930 {
14931 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14932  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14933  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14934  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14935  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14936 */
14937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14939  bool FoundFlag, ContFlag, FoundElements = false;
14940  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14941  TPrefDirElement NextElement;
14942 
14943  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14944  {
14945  LastIteratorValue++;
14946  ContFlag = false;
14947  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14948  {
14949  continue;
14950  }
14951 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14952  {
14953  continue;
14954  }
14955 */
14956 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14957  // found a potential route start point
14958  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14959  {
14960  continue;
14961  }
14962  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14963  {
14964  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14965  if(PDVIt->TrackType == Continuation)
14966  {
14967  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14968  {
14969  continue;
14970  }
14971  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14972  {
14973  continue;
14974  }
14975  }
14976  StartElement = *PDVIt;
14977 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14978  // diverging track on which there was no pref dir. See below for 2 required changes.
14979  }
14980  else
14981  {
14982  continue;
14983  }
14984  // now track along until find a signal or continuation, checking validity for each element
14985  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14986  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14987  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14988  if(PrefDirPos0 == -1) // no continuing prefdir
14989  {
14990  continue;
14991  }
14992  bool NextElementFoundFlag = false;
14993  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14994  {
14995  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14996  NextElementFoundFlag = true;
14997  }
14998  if(PrefDirPos1 > -1)
14999  {
15000  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15001  {
15002  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15003  NextElementFoundFlag = true;
15004  }
15005  }
15006  if(PrefDirPos2 > -1)
15007  {
15008  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15009  {
15010  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15011  NextElementFoundFlag = true;
15012  }
15013  }
15014  if(PrefDirPos3 > -1)
15015  {
15016  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15017  {
15018  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15019  NextElementFoundFlag = true;
15020  }
15021  }
15022  if(!NextElementFoundFlag)
15023  {
15024  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15025 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15026  }
15027  while(true)
15028  {
15029  // check validity
15030  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15031  {
15032  ContFlag = true;
15033  break;
15034  }
15035  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15036  {
15037  ContFlag = true;
15038  break;
15039  }
15040  // check if in a route, providing not a signal, as a signal might be at the start of a route
15041  if(NextElement.TrackType != SignalPost)
15042  {
15043  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15044  {
15045  ContFlag = true;
15046  break;
15047  }
15048  }
15049  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15050  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15051  {
15052  EndElement = NextElement;
15053  break;
15054  }
15055  // get the next element in the sequence
15056  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15057  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15058  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15059  if(PrefDirPos0 == -1) // no continuing prefdir
15060  {
15061  ContFlag = true;
15062  break;
15063  }
15064  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15065  {
15066  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15067  continue;
15068  }
15069  if(PrefDirPos1 > -1)
15070  {
15071  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15072  {
15073  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15074  continue;
15075  }
15076  }
15077  if(PrefDirPos2 > -1)
15078  {
15079  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15080  {
15081  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15082  continue;
15083  }
15084  }
15085  if(PrefDirPos3 > -1)
15086  {
15087  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15088  {
15089  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15090  continue;
15091  }
15092  }
15093  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15094  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15095  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15096  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15097  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15098  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15099  {
15100  ContFlag = true;
15101  break;
15102  }
15103  else
15104  {
15105  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15106  // could drop the bridge test but keep it to show the change history
15107  break;
15108 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15109  }
15110  }
15111  if(ContFlag)
15112  {
15113  continue;
15114  }
15115  // else have start and end elements set & all elements valid, so set up the route segment
15116  FoundElements = true;
15117  break;
15118  }
15119  if(FoundElements)
15120  {
15121  Utilities->CallLogPop(1992);
15122  return(true);
15123  }
15124  else
15125  {
15126  Utilities->CallLogPop(1993);
15127  return(false);
15128  }
15129 }
15130 
15131 // ---------------------------------------------------------------------------
15132 // TOneRoute
15133 // ---------------------------------------------------------------------------
15134 
15135 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15136 {
15137 /* General:
15138  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15139  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15140  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15141  route will use automatic signals or not.
15142  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15143  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15144  elements, so additional work is needed to complete all their members before they are ready for conversion into
15145  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15146  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15147  ConvertAndAdd.......
15148 */
15149  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15150  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15151  ClearRoute();
15152  int TrackVectorPosition;
15153  TTrackElement TrackElement;
15154  TPrefDirElement FirstElement, LastElement;
15155 
15156  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15157  {
15158  Utilities->CallLogPop(199);
15159  return(false);
15160  }
15161  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15162  {
15163  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15164  Utilities->CallLogPop(1996);
15165  return(false);
15166  }
15167  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15168  {
15169  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation to start or add to a route, or points to change them");
15170  Utilities->CallLogPop(200);
15171  return(false);
15172  }
15173  if(Track->IsLCAtHV(18, HLoc, VLoc))
15174  {
15175  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15176  Utilities->CallLogPop(1909);
15177  return(false);
15178  }
15179 // check if selected a train & disallow if so
15180  if(TrackElement.TrainIDOnElement > -1)
15181  {
15182  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15183  Utilities->CallLogPop(202);
15184  return(false);
15185  }
15186 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15187  TPrefDirElement PrefDirElement;
15188  int LockedVectorNumber;
15189 
15190  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15191  {
15192  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15193  Utilities->CallLogPop(203);
15194  return(false);
15195  }
15196  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15197  {
15198  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15199  Utilities->CallLogPop(204);
15200  return(false);
15201  }
15203  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15204 // signal in an autosig route & follow with a non-autosig route
15205 
15206  TPrefDirElement BlankElement;
15207 
15208  StartElement1 = BlankElement;
15209  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15210 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15211  bool InPrefDirFlag = false;
15212 
15213  bool FoundFlag;
15214  int PrefDirPos0 = -1;
15215  int PrefDirPos1 = -1;
15216  int PrefDirPos2 = -1;
15217  int PrefDirPos3 = -1;
15218 
15220  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15221  int PrefDirVecPos[4] =
15222  {
15223  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15224  };
15225 
15226  for(int x = 0; x < 4; x++)
15227  {
15228  int b = PrefDirVecPos[x];
15229  if(b > -1)
15230  {
15231  // only allow the appropriate exit route to be searched
15232  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15233  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15234  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15235  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15236  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15237  {
15238  InPrefDirFlag = true;
15239  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15240  if(AutoSigsFlag)
15241  {
15242  StartElement1.AutoSignals = true;
15243  }
15244  StartElement1.PrefDirRoute = true;
15245  }
15246  }
15247  }
15248 
15249  if(!InPrefDirFlag)
15250  {
15251  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15252  Utilities->CallLogPop(205);
15253  return(false);
15254  }
15255 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15257  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15258 
15259  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15260  {
15261  throw Exception("Selection in two routes - should never happen!");
15262  }
15263  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15264  {
15265  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15266  {
15267  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15268  Utilities->CallLogPop(206);
15269  return(false);
15270  }
15271  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15272  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15273  {
15274  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15275  Utilities->CallLogPop(207);
15276  return(false);
15277  }
15278  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15279  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15280  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15281  { //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
15282 // TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15283 // Utilities->CallLogPop(208);
15284 // return(false);
15285  }
15286  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15288  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15289  if(AutoSigsFlag)
15290  {
15291  StartElement1.AutoSignals = true;
15292  }
15293  StartElement1.PrefDirRoute = true;
15295  Utilities->CallLogPop(209);
15296  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15297  }
15298 
15299  else // no route started
15300  {
15301 // check if selected position is adjacent to start or end of an existing route and disallow
15302  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15303  {
15304  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15305  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15306  {
15307  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15308  Utilities->CallLogPop(210);
15309  return(false);
15310  }
15311  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15312  {
15313  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15314  Utilities->CallLogPop(211);
15315  return(false);
15316  }
15317  }
15318 
15319 // check if it's adjacent to end of an existing route,
15320  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15321  {
15323  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15324  {
15325  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15326  Utilities->CallLogPop(212);
15327  return(false);
15328  }
15329  }
15330  SearchVector.push_back(StartElement1);
15331  Utilities->CallLogPop(213);
15332  return(true);
15333  }
15334 }
15335 
15336 // ---------------------------------------------------------------------------
15337 
15338 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15339  IDInt &ReqPosRouteID, bool &PointsChanged)
15340 
15341 /*
15342  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15343 
15344  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15345  this being set to -1 for not used.
15346  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15347  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15348  Check correct type of element - signal/buffers/continuation.
15349  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15350  EndElement2 corresponding to the 2 possible PrefDir elements).
15351  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15352  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15353  linked forward to another route.
15354  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15355  for same position as start should cover this)
15356 
15357  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15358  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15359  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15360  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15361  If the search fails then return false.
15362  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15363  in the SearchVector to ensure it's entered as part of the new route.
15364  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15365  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15366  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15367  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15368  so return false, with an appropriate message if ConsecSignalsRoute set.
15369 */
15370 
15371 {
15372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15373  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15374  int EndPosition; // the position selected
15375  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15376 
15377  Track->LCFoundInAutoSigsRoute = false;
15379  TotalSearchCount = 0;
15380  ReqPosRouteID = IDInt(-1); // default value for not used
15381  TTrackElement TrackElement;
15382  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15383  // given element as can't select 2-track elements
15384  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15385  {
15386  Utilities->CallLogPop(214);
15387  return(false);
15388  }
15389  if(Track->IsLCAtHV(19, HLoc, VLoc))
15390  {
15391  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15392  Utilities->CallLogPop(1908);
15393  return(false);
15394  }
15395 // cancel selection if on original start element
15396  if(EndPosition == StartRoutePosition)
15397  {
15398  Utilities->CallLogPop(215);
15399  return(false);
15400  }
15401  if(AutoSigsFlag)
15402  {
15403  if(TrackElement.TrackType == Buffers)
15404  {
15405  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15406  Utilities->CallLogPop(216);
15407  return(false);
15408  }
15409  }
15410  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15411  {
15412  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15413  Utilities->CallLogPop(217);
15414  return(false);
15415  }
15416 // check if train on element
15417  if(TrackElement.TrainIDOnElement > -1)
15418  {
15419  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15420  Utilities->CallLogPop(219);
15421  return(false);
15422  }
15423 // disallow if not in EveryPrefDir & set EndElement(s)
15424  bool InPrefDirFlag = false;
15425 
15426  bool FoundFlag;
15427  int PrefDirPos0 = -1;
15428  int PrefDirPos1 = -1;
15429  int PrefDirPos2 = -1;
15430  int PrefDirPos3 = -1;
15431 
15432  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15433  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15434  int PrefDirVecPos[4] =
15435  {
15436  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15437  };
15438 
15439  for(int x = 0; x < 4; x++)
15440  {
15441  int b = PrefDirVecPos[x];
15442  if(b > -1)
15443  {
15444  InPrefDirFlag = true;
15445  if(EndElement1.TrackVectorPosition == -1)
15446  {
15447  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15448  }
15449  else
15450  {
15451  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15452  }
15453  }
15454  }
15455  if(!InPrefDirFlag)
15456  {
15457  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15458  Utilities->CallLogPop(220);
15459  return(false);
15460  }
15461 // check if in an existing route - can't be a bridge so can use a simple 'find'
15462 // bool InRoute = false;
15464  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15465 
15466  if(RoutePair.first > -1)
15467  {
15468  if(RoutePair.second != 0) // not first element in existing route so no good
15469  {
15470  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15471  Utilities->CallLogPop(221);
15472  return(false);
15473  }
15474  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15475 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15476  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15477  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15478  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15479  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15480  {
15481  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15482  Utilities->CallLogPop(222);
15483  return(false);
15484  }
15485  EndElement1 = RouteElement;
15486  EndElement2 = BlankElement; // only need the route element
15487  EndPosition = EndElement1.TrackVectorPosition;
15488  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15489  }
15490 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15491 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15492 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15493 
15494  if(EndElement1.HLoc >= StartElement1.HLoc)
15495  {
15497  SearchLimitHighH = EndElement1.HLoc + 15;
15498  }
15499  else
15500  {
15501  SearchLimitLowH = EndElement1.HLoc - 15;
15503  }
15504  if(EndElement1.VLoc >= StartElement1.VLoc)
15505  {
15507  SearchLimitHighV = EndElement1.VLoc + 15;
15508  }
15509  else
15510  {
15511  SearchLimitLowV = EndElement1.VLoc - 15;
15513  }
15514 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15515  check & TotalSearchCounts check
15516  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15517  {
15518  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15519  Utilities->CallLogPop(1693);
15520  return false;
15521  }
15522 */
15523 // check if adjacent to start and disallow
15524  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15525  {
15527  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15528 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15529 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15530  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15531  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15532  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15533  {
15534  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15535  Utilities->CallLogPop(223);
15536  return(false);
15537  }
15538 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15539 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15540  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15541  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15542  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15543  {
15544  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15545  Utilities->CallLogPop(224);
15546  return(false);
15547  }
15548 // check if adjacent to end of a route & disallow
15550  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15551  {
15552  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15553  Utilities->CallLogPop(225);
15554  return(false);
15555  }
15556  }
15557 
15558 // check for same route as start element
15560  {
15561  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15562  Utilities->CallLogPop(226);
15563  return(false);
15564  }
15565 // check for a looping route
15566  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15567  {
15569  {
15570  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15571  Utilities->CallLogPop(1844);
15572  return(false);
15573  }
15574  }
15575 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15576 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15577 // and don't want to add it again
15578  if(StartSelectionRouteID > -1)
15579  {
15580  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15581  AutoSigsFlag, false))
15582  {
15583  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15584  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15585  {
15586  if(NewFailedPointsTVPos > -1)
15587  {
15588  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15589  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15590  " failed during route setting.");
15591  Utilities->CallLogPop(2488);
15592  return(false);
15593  }
15594  PointsChanged = true;
15595  }
15596  Utilities->CallLogPop(227);
15597  return(true);
15598  }
15599  else if(!Track->SuppressRouteFailMessage)
15600  {
15601  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15603  Utilities->CallLogPop(228);
15604  return(false);
15605  }
15606  }
15607  else
15608  {
15609 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15610 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15611 
15612 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15613 // note that a blank element will have XLinkPos set to -1
15614  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15615  {
15616  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15617  AutoSigsFlag, false))
15618  {
15619  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15620  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15621  {
15622  if(NewFailedPointsTVPos > -1)
15623  {
15624  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15625  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15626  " failed during route setting.");
15627  Utilities->CallLogPop(2490);
15628  return(false);
15629  }
15630  PointsChanged = true;
15631  }
15632  Utilities->CallLogPop(229);
15633  return(true);
15634  }
15635  else
15636  {
15638  {
15640  }
15641  Utilities->CallLogPop(230);
15642  return(false);
15643  }
15644  }
15645  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15646  {
15647  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15648  AutoSigsFlag, false))
15649  {
15650  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15651  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15652  {
15653  if(NewFailedPointsTVPos > -1)
15654  {
15655  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15656  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15657  " failed during route setting.");
15658  Utilities->CallLogPop(2492);
15659  return(false);
15660  }
15661  PointsChanged = true;
15662  }
15663  Utilities->CallLogPop(231);
15664  return(true);
15665  }
15666  else
15667  {
15669  {
15671  }
15672  Utilities->CallLogPop(232);
15673  return(false);
15674  }
15675  }
15676  // now start off in the best direction
15677  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15678  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15679  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15680  // unless new problems are found.
15681  if(StartElement1.XLinkPos == BestPos)
15682  {
15683  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15684  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15685  AutoSigsFlag, false))
15686  {
15687  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15688  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15689  {
15690  if(NewFailedPointsTVPos > -1)
15691  {
15692  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15693  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15694  " failed during route setting.");
15695  Utilities->CallLogPop(2494);
15696  return(false);
15697  }
15698  PointsChanged = true;
15699  }
15700  Utilities->CallLogPop(233);
15701  return(true);
15702  }
15703  else if(StartElement2.TrackVectorPosition > -1)
15704  {
15705  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15706  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15707  AutoSigsFlag, false))
15708  {
15709  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15710  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15711  {
15712  if(NewFailedPointsTVPos > -1)
15713  {
15714  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15715  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15716  " failed during route setting.");
15717  Utilities->CallLogPop(2496);
15718  return(false);
15719  }
15720  PointsChanged = true;
15721  }
15722  Utilities->CallLogPop(234);
15723  return(true);
15724  }
15725  }
15726  }
15727  else if(StartElement2.TrackVectorPosition > -1)
15728  {
15729  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15730  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15731  AutoSigsFlag, false))
15732  {
15733  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15734  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15735  {
15736  if(NewFailedPointsTVPos > -1)
15737  {
15738  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15739  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15740  " failed during route setting.");
15741  Utilities->CallLogPop(2498);
15742  return(false);
15743  }
15744  PointsChanged = true;
15745  }
15746  Utilities->CallLogPop(1857);
15747  return(true);
15748  }
15749  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15750  AutoSigsFlag, false))
15751  {
15752  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15753  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15754  {
15755  if(NewFailedPointsTVPos > -1)
15756  {
15757  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15758  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15759  " failed during route setting.");
15760  Utilities->CallLogPop(2500);
15761  return(false);
15762  }
15763  PointsChanged = true;
15764  }
15765  Utilities->CallLogPop(1858);
15766  return(true);
15767  }
15768  }
15769  else if(StartElement1.XLinkPos == (1 - BestPos))
15770  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15771  {
15772  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15773  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15774  AutoSigsFlag, false))
15775  {
15776  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15777  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15778  {
15779  if(NewFailedPointsTVPos > -1)
15780  {
15781  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15782  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15783  " failed during route setting.");
15784  Utilities->CallLogPop(2502);
15785  return(false);
15786  }
15787  PointsChanged = true;
15788  }
15789  Utilities->CallLogPop(1864);
15790  return(true);
15791  }
15792  }
15793  }
15795  {
15797  }
15798  Utilities->CallLogPop(235);
15799  return(false);
15800 }
15801 
15802 // ---------------------------------------------------------------------------
15803 
15804 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15805 {
15806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15807  if(PrefDirSize() == 0)
15808  {
15809  Utilities->CallLogPop(1704);
15810  return;
15811  }
15812  for(unsigned int x = 0; x < PrefDirSize(); x++)
15813  {
15814  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15815  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15816  {
15817  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15818  TempPrefDirElement.EXGraphicPtr);
15819  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15820  {
15821  if(x == 0)
15822  {
15823  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15824  TempPrefDirElement.EntryDirectionGraphicPtr);
15825  }
15826  if(x == (PrefDirSize() - 1))
15827  {
15828  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15829  TempPrefDirElement.EntryDirectionGraphicPtr);
15830  }
15831  }
15832  }
15833  }
15834 
15835  Utilities->CallLogPop(1705);
15836 }
15837 
15838 // ---------------------------------------------------------------------------
15839 
15840 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15841  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15842 /*
15843  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15844  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15845  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15846  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15847  Return false if any element (apart from RequiredPosition) is on an existing route.
15848  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15849 
15850  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15851  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15852  added during the function so as to leave it exactly as it was on entering, then return false).
15853  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15854  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15855  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15856  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15857  the route number that the searched-for element is the start of if any, and set to -1 if no
15858  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15859  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15860  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15861  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15862 
15863  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15864  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15865  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15866  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15867  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15868  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15869  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15870  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15871  or if train on element (unless a bridge & train on different track).
15872  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15873  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15874  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15875  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15876  AutoSignals member set if AutoSigsFlag set, then return true.
15877  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15878 
15879  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15880  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15881  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15882  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15883  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15884  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15885  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15886 
15887  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15888  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15889 */
15890 
15891 {
15892  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15893  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15894  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
15895  int VectorCount = 0;
15896  if(!RecursiveCall) //added at v2.15.1
15897  {
15899  }
15900 
15901  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15902 
15903 // check for a fouled diagonal for first element. Added for v1.3.2
15904  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15905  {
15906  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15907  {
15908  for(int x = 0; x < VectorCount; x++)
15909  {
15910  SearchVector.erase(SearchVector.end() - 1);
15911  }
15912  Utilities->CallLogPop(2043);
15913  return(false);
15914  }
15915  }
15916  bool FirstPass = true;
15917 
15918  while(true)
15919  {
15920  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15921  {
15922  Track->LCFoundInAutoSigsRoute = true;
15923  }
15924  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15925  {
15926  for(int x = 0; x < VectorCount; x++)
15927  {
15928  SearchVector.erase(SearchVector.end() - 1);
15929  }
15930  Utilities->CallLogPop(1926);
15931  return(false);
15932  }
15933  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15934  {
15935  for(int x = 0; x < VectorCount; x++)
15936  {
15937  SearchVector.erase(SearchVector.end() - 1);
15938  }
15939  Utilities->CallLogPop(236);
15940  return(false);
15941  }
15942  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15943  // reached a valid signal that isn't the required position, user should always select the next
15944  // signal in a route when ConsecSignals is true so have to fail
15945  // won't affect recurive searches as for them the first pass element is always a point
15946  {
15947  for(int x = 0; x < VectorCount; x++)
15948  {
15949  SearchVector.erase(SearchVector.end() - 1);
15950  }
15951  Utilities->CallLogPop(237);
15952  return(false);
15953  }
15954  FirstPass = false;
15955  int NextPosition = PrefDirElement.Conn[XLinkPos];
15956  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15957  TPrefDirElement SearchElement(NextTrackElement);
15958  SearchElement.TrackVectorPosition = NextPosition;
15959  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15960  SearchElement.ELinkPos = NextELinkPos;
15961  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15962  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15963  int NextXLinkPos;
15964  if(SearchElement.ELinkPos == 0)
15965  {
15966  NextXLinkPos = 1;
15967  }
15968  if(SearchElement.ELinkPos == 1)
15969  {
15970  NextXLinkPos = 0;
15971  }
15972  if(SearchElement.ELinkPos == 2)
15973  {
15974  NextXLinkPos = 3;
15975  }
15976  if(SearchElement.ELinkPos == 3)
15977  {
15978  NextXLinkPos = 2;
15979  }
15980  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15981  {
15982  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15983 // note that may be buffers, continuation or gap
15984  SearchElement.XLinkPos = NextXLinkPos;
15985  }
15986 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15987 
15988 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15989  drop this at v2.16.1 as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of points and
15990  crossovers as can reach element on opposite track and still find the required end point - causes error when adding to the Route2MultiMap
15991  (happened by chance when developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search
15992  through all searchvector.
15993 
15994  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
15995 */
15996  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
15997  {
15998  for(unsigned int x = 0; x < SearchVector.size(); x++)
15999  {
16000  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
16001  {
16002  for(int x = 0; x < VectorCount; x++)
16003  {
16004  SearchVector.erase(SearchVector.end() - 1);
16005  }
16006  Utilities->CallLogPop(2653);
16007  return(false);
16008  }
16009  }
16010  }
16011  else if(SearchElement.TrackType == Bridge)
16012  {
16013  for(unsigned int x = 0; x < SearchVector.size(); x++)
16014  {
16015  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16016  (SearchElement.ELink == SearchVector.at(x).ELink))
16017  {
16018  for(int x = 0; x < VectorCount; x++)
16019  {
16020  SearchVector.erase(SearchVector.end() - 1);
16021  }
16022  Utilities->CallLogPop(2654);
16023  return(false);
16024  }
16025  }
16026  }
16027 
16028 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16029  TAllRoutes::TRouteElementPair SecondPair;
16031  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16032  if(RoutePair.first > -1)
16033  {
16034  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16035  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16036  RoutePair.second).ELinkPos)))
16037  {
16038  // still OK if start of an expected route
16039  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16040  {
16041  for(int x = 0; x < VectorCount; x++)
16042  {
16043  SearchVector.erase(SearchVector.end() - 1);
16044  }
16045  Utilities->CallLogPop(239);
16046  return(false); // only allow for start of an expected route
16047  }
16048  }
16049  }
16050  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16051  {
16052  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16053  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16054  SecondPair.second).ELinkPos)))
16055  {
16056  // still OK if start of an expected route
16057  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16058  {
16059  for(int x = 0; x < VectorCount; x++)
16060  {
16061  SearchVector.erase(SearchVector.end() - 1);
16062  }
16063  Utilities->CallLogPop(240);
16064  return(false); // only allow for start of an expected route
16065  }
16066  }
16067  }
16068 // check if a train on element, unless a bridge & train on different track
16069 // OK of same train as start element - no drop this
16070 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16071  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16072  {
16073  for(int x = 0; x < VectorCount; x++)
16074  {
16075  SearchVector.erase(SearchVector.end() - 1);
16076  }
16077  Utilities->CallLogPop(241);
16078  return(false);
16079  }
16080  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16081  {
16082  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16083  {
16084  for(int x = 0; x < VectorCount; x++)
16085  {
16086  SearchVector.erase(SearchVector.end() - 1);
16087  }
16088  Utilities->CallLogPop(242);
16089  return(false);
16090  }
16091  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16092  {
16093  for(int x = 0; x < VectorCount; x++)
16094  {
16095  SearchVector.erase(SearchVector.end() - 1);
16096  }
16097  Utilities->CallLogPop(243);
16098  return(false);
16099  }
16100  }
16101 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16102  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16103  {
16104  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16105  {
16106  for(int x = 0; x < VectorCount; x++)
16107  {
16108  SearchVector.erase(SearchVector.end() - 1);
16109  }
16110  Utilities->CallLogPop(244);
16111  return(false);
16112  }
16113  }
16114 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16115 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16116  bool InPrefDirFlag = false;
16117  PrefDirElement1 = BlankElement;
16118  PrefDirElement2 = BlankElement;
16119 
16120  bool FoundFlag;
16121  int PrefDirPos0 = -1;
16122  int PrefDirPos1 = -1;
16123  int PrefDirPos2 = -1;
16124  int PrefDirPos3 = -1;
16126  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16127  int PrefDirVecPos[4] =
16128  {
16129  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16130  };
16131  for(int x = 0; x < 4; x++)
16132  {
16133  int b = PrefDirVecPos[x];
16134  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16135  {
16136  InPrefDirFlag = true;
16137  if(PrefDirElement1.TrackVectorPosition == -1)
16138  {
16139  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16140  }
16141  else
16142  {
16143  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16144  }
16145  }
16146  }
16147  if(!InPrefDirFlag)
16148  {
16149  for(int x = 0; x < VectorCount; x++)
16150  {
16151  SearchVector.erase(SearchVector.end() - 1);
16152  }
16153  Utilities->CallLogPop(245);
16154  return(false);
16155  }
16156 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16157 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16158 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16160  {
16161  for(int x = 0; x < VectorCount; x++)
16162  {
16163  SearchVector.erase(SearchVector.end() - 1);
16164  }
16165  Utilities->CallLogPop(1690);
16166  return(false);
16167  }
16168 // check if found it
16169  if(SearchElement.TrackVectorPosition == RequiredPosition)
16170  {
16171 // need to ensure a signal/buffer/continuation
16172 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16173  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16174  {
16175  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16177  for(int x = 0; x < VectorCount; x++)
16178  {
16179  SearchVector.erase(SearchVector.end() - 1);
16180  }
16181  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16182  Utilities->CallLogPop(246);
16183  return(false);
16184  } // if((SearchElement.TrackType != SignalPost) &&.......
16185 //need to make sure it's in the right direction
16186  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16187  { //condition added at v2.16.1
16188  for(int x = 0; x < VectorCount; x++)
16189  {
16190  SearchVector.erase(SearchVector.end() - 1);
16191  }
16192  Utilities->CallLogPop(2627);
16193  return(false);
16194  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16195 
16196  if(AutoSigsFlag)
16197  {
16198  PrefDirElement1.AutoSignals = true;
16199  }
16200  PrefDirElement1.PrefDirRoute = true;
16202  {
16204  {
16205  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16207  }
16208  for(int x = 0; x < VectorCount; x++)
16209  {
16210  SearchVector.erase(SearchVector.end() - 1);
16211  }
16212  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16213  Utilities->CallLogPop(1928);
16214  return(false);
16215  }
16216  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16217  VectorCount++; // not really needed but include for tidyness
16218  TotalSearchCount++;
16219  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16220  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16221  for(int x = 0; x < VectorCount; x++)
16222  {
16223  SearchVector.erase(SearchVector.end() - 1);
16224  }
16225  Utilities->CallLogPop(2522);
16226  return(false);
16227  }
16228  Utilities->CallLogPop(247);
16229  return(true);
16230  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16231 
16232 // check if a buffer or continuation (end of search on this leg if not found by now)
16233  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16234  {
16235  for(int x = 0; x < VectorCount; x++)
16236  {
16237  SearchVector.erase(SearchVector.end() - 1);
16238  }
16239  Utilities->CallLogPop(248);
16240  return(false);
16241  }
16242 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16244  {
16245  for(int x = 0; x < VectorCount; x++)
16246  {
16247  SearchVector.erase(SearchVector.end() - 1);
16248  }
16249  Utilities->CallLogPop(1420);
16250  return(false);
16251  }
16252 //deal with failed points, added at v2.13.0
16253  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16254  {
16255  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16256  {
16257  SearchElement.XLinkPos = 1;
16258  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16259  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16260  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16261  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16262  }
16263  else
16264  {
16265  SearchElement.XLinkPos = 3;
16266  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16267  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16268  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16269  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16270  }
16271  }
16272  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16273  {
16274  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16275  {
16276  for(int x = 0; x < VectorCount; x++)
16277  {
16278  SearchVector.erase(SearchVector.end() - 1);
16279  }
16280  Utilities->CallLogPop(2514);
16281  return(false);
16282  }
16283  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16284  {
16285  for(int x = 0; x < VectorCount; x++)
16286  {
16287  SearchVector.erase(SearchVector.end() - 1);
16288  }
16289  Utilities->CallLogPop(2515);
16290  return(false);
16291  }
16292  }
16293 // check if reached a non-failed leading point
16294  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16295  {
16296 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16297  int SearchPos1 = SearchElement.Attribute + 1;
16298  int SearchPos2;
16299  if(SearchPos1 == 2)
16300  {
16301  SearchPos1++;
16302  }
16303  if(SearchPos1 == 1)
16304  {
16305  SearchPos2 = 3;
16306  }
16307  else
16308  {
16309  SearchPos2 = 1;
16310  }
16311  SearchElement.XLink = SearchElement.Link[SearchPos1];
16312  SearchElement.XLinkPos = SearchPos1;
16313  InPrefDirFlag = false;
16314  if(SearchElement.XLink == PrefDirElement1.XLink)
16315  {
16316  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16317  InPrefDirFlag = true;
16318  }
16319  else if(SearchElement.XLink == PrefDirElement2.XLink)
16320  {
16321  SearchElement = PrefDirElement2;
16322  InPrefDirFlag = true;
16323  }
16324 // push element with XLink set to position [SearchPos1] if on a PrefDir
16325  if(InPrefDirFlag)
16326  {
16327 // check for a fouled diagonal for leading point for XLinkPos == 1)
16328  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16329  {
16330  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16331  {
16332  for(int x = 0; x < VectorCount; x++)
16333  {
16334  SearchVector.erase(SearchVector.end() - 1);
16335  }
16336  Utilities->CallLogPop(249);
16337  return(false);
16338  }
16339  }
16340  if(AutoSigsFlag)
16341  {
16342  SearchElement.AutoSignals = true;
16343  }
16344  SearchElement.PrefDirRoute = true;
16345  SearchVector.push_back(SearchElement);
16346  VectorCount++;
16347  TotalSearchCount++;
16348 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16349  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16350  AutoSigsFlag, true))
16351  {
16353  {
16355  {
16356  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16358  }
16359  for(int x = 0; x < VectorCount; x++)
16360  {
16361  SearchVector.erase(SearchVector.end() - 1);
16362  }
16363  Utilities->CallLogPop(1929);
16364  return(false);
16365  }
16366  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16367  {
16368  for(int x = 0; x < VectorCount; x++)
16369  {
16370  SearchVector.erase(SearchVector.end() - 1);
16371  }
16372  Utilities->CallLogPop(2523);
16373  return(false);
16374  }
16375  Utilities->CallLogPop(250);
16376  return(true);
16377  }
16378  else
16379  {
16380 // remove leading point with XLinkPos [1]
16381  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16382  {
16383  SearchVector.erase(SearchVector.end() - 1);
16384  VectorCount--;
16385  }
16386  else
16387  {
16388  for(int x = 0; x < VectorCount; x++)
16389  {
16390  SearchVector.erase(SearchVector.end() - 1);
16391  }
16392  Utilities->CallLogPop(2626);
16393  return(false);
16394  }
16395  }
16396  }
16397 // XLink set to position [SearchPos2]
16398  SearchElement.XLink = SearchElement.Link[SearchPos2];
16399  SearchElement.XLinkPos = SearchPos2;
16400  if(SearchElement.XLink == PrefDirElement1.XLink)
16401  {
16402  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16403  }
16404  else if(SearchElement.XLink == PrefDirElement2.XLink)
16405  {
16406  SearchElement = PrefDirElement2;
16407  }
16408  else // failed to find a valid exit from the point
16409  {
16410  for(int x = 0; x < VectorCount; x++)
16411  {
16412  SearchVector.erase(SearchVector.end() - 1);
16413  }
16414  Utilities->CallLogPop(251);
16415  return(false);
16416  }
16417 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16418  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16419  {
16420  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16421  {
16422  for(int x = 0; x < VectorCount; x++)
16423  {
16424  SearchVector.erase(SearchVector.end() - 1);
16425  }
16426  Utilities->CallLogPop(252);
16427  return(false);
16428  }
16429  }
16430 // push element with XLink set to position [SearchPos2]
16431  if(AutoSigsFlag)
16432  {
16433  SearchElement.AutoSignals = true;
16434  }
16435  SearchElement.PrefDirRoute = true;
16436  SearchVector.push_back(SearchElement);
16437  VectorCount++;
16438  TotalSearchCount++;
16439 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16440  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16441  AutoSigsFlag, true))
16442  {
16444  {
16446  {
16447  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16449  }
16450  for(int x = 0; x < VectorCount; x++)
16451  {
16452  SearchVector.erase(SearchVector.end() - 1);
16453  }
16454  Utilities->CallLogPop(1930);
16455  return(false);
16456  }
16457  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16458  {
16459  for(int x = 0; x < VectorCount; x++)
16460  {
16461  SearchVector.erase(SearchVector.end() - 1);
16462  }
16463  Utilities->CallLogPop(2524);
16464  return(false);
16465  }
16466  Utilities->CallLogPop(1592);
16467  return(true);
16468  }
16469  else
16470  {
16471  for(int x = 0; x < VectorCount; x++)
16472  {
16473  SearchVector.erase(SearchVector.end() - 1);
16474  }
16475  Utilities->CallLogPop(253);
16476  return(false);
16477  }
16478  } // if leading point
16479 
16480 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16481  SearchElement = PrefDirElement1;
16482  if(AutoSigsFlag)
16483  {
16484  SearchElement.AutoSignals = true;
16485  }
16486  SearchElement.PrefDirRoute = true;
16487  SearchVector.push_back(SearchElement);
16488  VectorCount++;
16489  TotalSearchCount++;
16490  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16491  PrefDirElement = SearchElement;
16492  } // while(true)
16493 }
16494 
16495 // ---------------------------------------------------------------------------
16496 
16497 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16498 {
16499 /*
16500  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16501  and the new or extended route created from that. Hence action varies depending on whether
16502  it is a completely new route, or an extension of an existing route at the beginning or the end.
16503  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16504  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16505 
16506  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16507  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16508  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16509  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16510  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16511  is decremented;
16512  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16513  from the existing route, then enter the new route into the AllRoutesVector;
16514  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16515  then enter the new route into the AllRoutesVector.
16516 
16517  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16518  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16519  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16520  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16521  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16522  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16523  for the new route and return;
16524  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16525  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16526 
16527  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16528  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16529  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16530 
16531 */
16532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16533  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16534  if(SearchVector.size() < 1)
16535  {
16536  Utilities->CallLogPop(254);
16537  return;
16538  }
16540  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16541  {
16542  Utilities->CallLogPop(255);
16543  return;
16544  }
16545  TAllRoutes::TLockedRouteClass LockedRouteObject;
16546 
16548  unsigned int TruncatePrefDirPosition = 0;
16549 
16550  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16551 /* if have ReqPosRouteID:
16552  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16553  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16554  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16555  the existing route, then enter the new route into the AllRoutesVector
16556  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16557  then enter the new route into the AllRoutesVector
16558 */
16559  {
16562  {
16563  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16564  x++) // start at 1 as first element already in SearchVector
16565  {
16567  }
16568  // note that route numbers in map adjusted when ReqPos route cleared
16570  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16571  // set during ClearRouteDuringRouteBuildingAt
16573  {
16576  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16577  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16578  }
16579  }
16581  {
16583  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16584  }
16586  {
16587  SearchVector.pop_back();
16588  }
16589  }
16590  if(StartSelectionRouteID > -1)
16591 /* if have StartSelectionRouteID:
16592  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16593  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16594  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16595  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16596  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16597 */
16598  {
16600  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16601  {
16604  {
16605  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16606  for(unsigned int x = 0; x < SearchVector.size(); x++)
16607  {
16609  RouteNumber, GetFixedSearchElementAt(3, x));
16610  // find & store locked route truncate position in PrefDirVector for later use
16612  {
16613  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16614  {
16615  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16616  }
16617  }
16618  }
16620  {
16621  throw Exception("Error - failed to validate extended route for preferred route");
16622  }
16625  if(!AutoSigsFlag)
16626  {
16627  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16628  }
16629  // now add the reinstated locked route if required and set signals accordingly
16631  {
16632  LockedRouteObject.RouteNumber = RouteNumber;
16633  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16634  // now reset the signals for the locked route
16635  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16636  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16637  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16638  {
16639  // return all signals to red in route section to be truncated
16640  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16641  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16642  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16643  {
16644  TrackElement.Attribute = 0;
16645  Track->PlotSignal(10, TrackElement, Display);
16646  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16647  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16648  }
16649  }
16650  }
16651  AllRoutes->CheckMapAndRoutes(1); // test
16652  Utilities->CallLogPop(256);
16653  return;
16654  }
16656  {
16659  RouteElement.AutoSignals = true;
16660  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16661  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16662  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16663  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16664  }
16665  }
16666  else
16667  {
16669  }
16670 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16671 // AllRoutesVector hence nothing to do here
16672  }
16673  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16674  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16675  {
16676  throw Exception("Error - failed to validate single route for preferred route");
16677  }
16678  AllRoutes->StoreOneRoute(1, this);
16679  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16680  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16681  if(!AutoSigsFlag)
16682  {
16683  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16684  }
16685  AllRoutes->CheckMapAndRoutes(2); // test
16686  Utilities->CallLogPop(257);
16687 }
16688 
16689 // ---------------------------------------------------------------------------
16690 
16691 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16692 {
16693 /*
16694  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16695  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16696  & ensure signal/buffers/continuation.
16697  Note that can't select ConsecSignalsRoute for non-preferred routes.
16698  Check if train on element & disallow.
16699  Set default values for retained parameters:-
16700  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16701  StartSelectionRouteID = route that selection starts in if there is one;
16702 
16703  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16704  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16705  validity. This is just for safety reasons, the PrefDir values aren't used.
16706  StartElement1 & 2 are set to these PrefDirelements.
16707 
16708  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16709 
16710  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16711  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16712  blank StartElement2 (only want to use the route element), then return true.
16713  Check if adjacent to start or end of an existing route & disallow if so.
16714  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16715  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16716  SetRemainingSearchVectorValues().
16717  Finally add the required element to the SearchVector & return true.
16718 
16719 */
16720  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16721  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16722  ClearRoute();
16723  int TrackVectorPosition;
16724  TTrackElement TrackElement;
16725  TPrefDirElement FirstElement, LastElement;
16726 
16727  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16728  {
16729  Utilities->CallLogPop(258);
16730  return(false);
16731  }
16732  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16733  {
16734  if(!Callon)
16735  {
16736  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16737  }
16738 // makes later adjacent route checks too complicated
16739  Utilities->CallLogPop(259);
16740  return(false);
16741  }
16742  if(Track->IsLCAtHV(21, HLoc, VLoc))
16743  {
16744  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16745  Utilities->CallLogPop(1910);
16746  return(false);
16747  }
16748 // check if selected a train & disallow if so
16749  if(TrackElement.TrainIDOnElement > -1)
16750  {
16751  if(!Callon)
16752  {
16753  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16754  }
16755  Utilities->CallLogPop(260);
16756  return(false);
16757  }
16758 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16759  TPrefDirElement PrefDirElement;
16760  int LockedVectorNumber;
16761 
16762  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16763  {
16764  if(!Callon)
16765  {
16766  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16767  }
16768  Utilities->CallLogPop(261);
16769  return(false);
16770  }
16771  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16772  {
16773  if(!Callon)
16774  {
16775  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16776  }
16777  Utilities->CallLogPop(262);
16778  return(false);
16779  }
16781 // AdjacentStartRouteNumber = -1;
16782  StartRoutePosition = TrackVectorPosition;
16783 // StartRouteSelectPosition = TrackVectorPosition;
16784 
16785  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16786  TPrefDirElement PrefDirElement2(TrackElement);
16787 
16788  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16789  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16790  TPrefDirElement BlankElement;
16791 
16792  PrefDirElement1.ELinkPos = 0;
16793  PrefDirElement1.XLinkPos = 1;
16794  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16795  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16796  if(!(PrefDirElement1.EntryExitNumber()))
16797  {
16798  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16799  // no need for bridge check as bridge selections not allowed
16800  }
16801  PrefDirElement1.CheckCount = 9;
16802  PrefDirElement2.ELinkPos = 1;
16803  PrefDirElement2.XLinkPos = 0;
16804  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16805  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16806  if(!(PrefDirElement2.EntryExitNumber()))
16807  {
16808  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16809  }
16810  PrefDirElement2.CheckCount = 9; // both now set
16811 
16812 // set StartElements to the above PrefDirElements
16813  StartElement1 = PrefDirElement1;
16814  StartElement2 = PrefDirElement2;
16815 
16816 // no PrefDir check needed as doesn't need to be in a PrefDir
16817 
16818 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16820  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16821 
16822  if(RoutePair.first > -1)
16823  {
16824  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16825  {
16826  if(!Callon)
16827  {
16828  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16829  }
16830  Utilities->CallLogPop(263);
16831  return(false);
16832  }
16833  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16834  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16835  {
16836  if(!Callon)
16837  {
16838  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16839  }
16840  Utilities->CallLogPop(264);
16841  return(false);
16842  }
16843  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16844  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16845  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16846  {
16847 // if(!Callon) //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
16848 // {
16849 // TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16850 // }
16851 // Utilities->CallLogPop(265);
16852 // return(false);
16853  }
16854  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16856  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16857  StartElement2 = BlankElement; // only use the route element
16859  Utilities->CallLogPop(266);
16860  return(true); // all retained values set
16861  }
16862 
16863  else // selection not in an existing route
16864  {
16865 // check if it's adjacent to start of an an existing route,
16866  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16867  {
16868  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16869  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16870  {
16871  if(!Callon)
16872  {
16873  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16874  }
16875  Utilities->CallLogPop(267);
16876  return(false);
16877  }
16878  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16879  {
16880  if(!Callon)
16881  {
16882  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16883  }
16884  Utilities->CallLogPop(268);
16885  return(false);
16886  }
16887  }
16888 // check if it's adjacent to end of an an existing route,
16889  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16890  {
16892  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16893  {
16894  if(!Callon)
16895  {
16896  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16897  }
16898  Utilities->CallLogPop(269);
16899  return(false);
16900  }
16901  }
16902  // not in a route or adjacent to start or end of a route
16903  // in this case reset all variable values to -1 & CheckCount to 4
16904  StartElement1.ELink = -1;
16905  StartElement1.ELinkPos = -1;
16906  StartElement1.XLink = -1;
16907  StartElement1.XLinkPos = -1;
16908  StartElement1.EXNumber = -1;
16909  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16910  StartElement2 = BlankElement;
16911  SearchVector.push_back(StartElement1);
16912  Utilities->CallLogPop(270);
16913  return(true);
16914  }
16915 }
16916 
16917 // ---------------------------------------------------------------------------
16918 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16919 
16920 /*
16921  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16922 
16923  Declare the following integers:-
16924  EndPosition - TrackVectorPosition for the selection;
16925  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16926  Check if selection is a valid track element and set EndPosition.
16927  Cancel if select original start element, then check that not points, bridge or crossover.
16928  Check & fail if a train is present at the selection.
16929  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16930  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16931  No check needed for selection in EveryPrefDir.
16932  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16933  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16934  as don't need it if in a route.
16935  Check if selection adj to start or end of a route and disallow.
16936  Fail if select same route as starting route, though should already have failed earlier if this is so.
16937 
16938  If there's a StartSelectionRouteID then StartElement1 will be set to
16939  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16940  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16941  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16942  to add the new route to the AllRoutesVectorPtr.
16943  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16944  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16945  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16946  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16947  the search vector values and return.
16948  If not returned yet then have failed to find the required element so return false with no message.
16949 
16950 */
16951 
16952 {
16953 // get EndPosition
16954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16955  AnsiString(VLoc));
16956  int EndPosition;
16957  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16958 
16959  TotalSearchCount = 0;
16960  ReqPosRouteID = IDInt(-1); // for not used
16961  TTrackElement TrackElement;
16962  TPrefDirElement BlankElement;
16964 
16965  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16966  {
16967  Utilities->CallLogPop(271);
16968  return(false);
16969  }
16970 // EndPosition = EndSelectPosition;
16971 // cancel selection if on original start element
16972  if(EndPosition == StartRoutePosition)
16973  {
16974  Utilities->CallLogPop(272);
16975  return(false);
16976  }
16977  if(Track->IsLCAtHV(22, HLoc, VLoc))
16978  {
16979  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16980  Utilities->CallLogPop(1911);
16981  return(false);
16982  }
16983  if((TrackElement.TrackType == Points) && !Callon)
16984  {
16985  if(!Callon)
16986  {
16987  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16988  }
16989 // makes later adjacent route checks too complicated
16990  Utilities->CallLogPop(273);
16991  return(false);
16992  }
16993  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16994  {
16995  if(!Callon)
16996  {
16997  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16998  }
16999 // makes later adjacent route checks too complicated
17000  Utilities->CallLogPop(1861);
17001  return(false);
17002  }
17003 // check if train on element
17004  if(TrackElement.TrainIDOnElement > -1)
17005  {
17006  if(!Callon)
17007  {
17008  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17009  }
17010  Utilities->CallLogPop(274);
17011  return(false);
17012  }
17013 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17014 // check passed)
17015  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17016  TPrefDirElement EndElement2(TrackElement);
17017 
17018  EndElement1.TrackVectorPosition = EndPosition;
17019  EndElement2.TrackVectorPosition = EndPosition;
17020  EndElement1.ELinkPos = 0;
17021  EndElement1.XLinkPos = 1;
17022  EndElement1.ELink = EndElement1.Link[0];
17023  EndElement1.XLink = EndElement1.Link[1];
17024  if(!(EndElement1.EntryExitNumber()))
17025  {
17026  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17027  }
17028  EndElement1.CheckCount = 9;
17029  EndElement2.ELinkPos = 1;
17030  EndElement2.XLinkPos = 0;
17031  EndElement2.ELink = EndElement2.Link[1];
17032  EndElement2.XLink = EndElement2.Link[0];
17033  if(!(EndElement2.EntryExitNumber()))
17034  {
17035  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17036  }
17037  EndElement2.CheckCount = 9; // both now set
17038 
17039 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17040 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17041 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17042 
17043  if(EndElement1.HLoc >= StartElement1.HLoc)
17044  {
17046  SearchLimitHighH = EndElement1.HLoc + 15;
17047  }
17048  else
17049  {
17050  SearchLimitLowH = EndElement1.HLoc - 15;
17052  }
17053  if(EndElement1.VLoc >= StartElement1.VLoc)
17054  {
17056  SearchLimitHighV = EndElement1.VLoc + 15;
17057  }
17058  else
17059  {
17060  SearchLimitLowV = EndElement1.VLoc - 15;
17062  }
17063 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17064  check & TotalSearchCounts check
17065  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17066  {
17067  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17068  Utilities->CallLogPop(1694);
17069  return false;
17070  }
17071 */
17072 // don't need EveryPrefDir check for NonPreferredRoute
17073 
17074 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17075 // bool InRoute = false;
17077  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17078 
17079  if(RoutePair.first > -1)
17080  {
17081  if(RoutePair.second != 0) // not first element in existing route so no good
17082  {
17083  if(!Callon)
17084  {
17085  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17086  }
17087  Utilities->CallLogPop(275);
17088  return(false);
17089  }
17090  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17091 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17092  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17093  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17094  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17095  {
17096  if(!Callon)
17097  {
17098  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17099  }
17100  Utilities->CallLogPop(276);
17101  return(false);
17102  }
17103  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17104  EndElement2 = BlankElement; // only need the route element
17105  EndPosition = EndElement1.TrackVectorPosition;
17106  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17107  }
17108 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17109  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17110  {
17111  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17112  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17113 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17114 // && (AdjPosition != StartRoutePosition))
17115  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17116  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17117  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17118  {
17119  if(!Callon)
17120  {
17121  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17122  }
17123  Utilities->CallLogPop(277);
17124  return(false);
17125  }
17126 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17127 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17128  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17129  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17130  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17131  (AdjPosition != StartRoutePosition))
17132  {
17133  if(!Callon)
17134  {
17135  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17136  }
17137  Utilities->CallLogPop(278);
17138  return(false);
17139  }
17140 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17142  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17143  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17144  {
17145  if(!Callon)
17146  {
17147  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17148  }
17149  Utilities->CallLogPop(279);
17150  return(false);
17151  }
17152  }
17153 
17154 // check for same route as start element
17156  {
17157  if(!Callon)
17158  {
17159  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17160  }
17161  Utilities->CallLogPop(280);
17162  return(false);
17163  }
17164 // check for a looping route
17165  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17166  {
17168  {
17169  if(!Callon)
17170  {
17171  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17172  }
17173  Utilities->CallLogPop(1845);
17174  return(false);
17175  }
17176  }
17177 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17178 // so search from this element.
17179 
17180  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17181 
17182  if(StartSelectionRouteID > -1)
17183  {
17184  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17185  {
17187  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17188  {
17189  if(NewFailedPointsTVPos > -1)
17190  {
17191  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17192  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17193  " failed during route setting.");
17194  Utilities->CallLogPop(2504);
17195  return(false);
17196  }
17197  PointsChanged = true;
17198  }
17199  Utilities->CallLogPop(281);
17200  return(true);
17201  }
17202  else
17203  {
17204  if(!Callon && !Track->SuppressRouteFailMessage)
17205  {
17207  }
17208  Utilities->CallLogPop(282);
17209  return(false);
17210  }
17211  }
17212  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17213  // search on the 2 ways out of the element, which has to be a 2-ended element
17214  {
17215 // check if selection adjacent to start element and if so use that
17216  if(SearchVector.at(0).Conn[0] == EndPosition)
17217  {
17218  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17219  {
17221  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17222  {
17223  if(NewFailedPointsTVPos > -1)
17224  {
17225  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17226  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17227  " failed during route setting.");
17228  Utilities->CallLogPop(2506);
17229  return(false);
17230  }
17231  PointsChanged = true;
17232  }
17233  Utilities->CallLogPop(283);
17234  return(true);
17235  }
17236  else
17237  {
17238  if(!Callon && !Track->SuppressRouteFailMessage)
17239  {
17241  }
17242  Utilities->CallLogPop(284);
17243  return(false);
17244  }
17245  }
17246  else if(SearchVector.at(0).Conn[1] == EndPosition)
17247  {
17248  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17249  {
17251  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17252  {
17253  if(NewFailedPointsTVPos > -1)
17254  {
17255  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17256  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17257  " failed during route setting.");
17258  Utilities->CallLogPop(2508);
17259  return(false);
17260  }
17261  PointsChanged = true;
17262  }
17263  Utilities->CallLogPop(285);
17264  return(true);
17265  }
17266  else
17267  {
17268  if(!Callon && !Track->SuppressRouteFailMessage)
17269  {
17271  }
17272  Utilities->CallLogPop(286);
17273  return(false);
17274  }
17275  }
17276  // now start off in the best direction
17277  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17278 
17279  if(SearchVector.at(0).Config[BestPos] != End)
17280  {
17281  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17282  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17283  {
17285  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17286  {
17287  if(NewFailedPointsTVPos > -1)
17288  {
17289  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17290  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17291  " failed during route setting.");
17292  Utilities->CallLogPop(2510);
17293  return(false);
17294  }
17295  PointsChanged = true;
17296  }
17297  Utilities->CallLogPop(287);
17298  return(true);
17299  }
17300  }
17301  if(SearchVector.at(0).Config[1 - BestPos] != End)
17302  {
17303  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17304  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17305  {
17307  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17308  {
17309  if(NewFailedPointsTVPos > -1)
17310  {
17311  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17312  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17313  " failed during route setting.");
17314  Utilities->CallLogPop(2512);
17315  return(false);
17316  }
17317  PointsChanged = true;
17318  }
17319  Utilities->CallLogPop(288);
17320  return(true);
17321  }
17322  }
17323  }
17324  if(!Callon && !Track->SuppressRouteFailMessage)
17325  {
17327  }
17328  Utilities->CallLogPop(289);
17329  return(false);
17330 }
17331 
17332 // ---------------------------------------------------------------------------
17333 
17334 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17335 /*
17336  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17337  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17338  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17339  Keep a count of entries in SearchVector during the current function call, so that this number can be
17340  erased for an unproductive branch search.
17341  First check (within the loop) whether XLink leads to an End & return false if so.
17342  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17343  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17344  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17345  train on element (unless a bridge & train on different track), or if element
17346  fouls an existing diagonal route (except if element is a leading point - these checked later).
17347  Then check if found required element. If so save it & return true.
17348  If not the required element check if buffer or continuation, & if so erase all searchvector
17349  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17350  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17351  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17352  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17353  When return true have 8 items from CheckCount established, only waiting for EXNumber
17354 */
17355 {
17356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17357  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17358  int VectorCount = 0;
17359 
17360 // check for a fouled diagonal for first element. Added for v1.3.2
17361  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17362  (CurrentTrackElement.Link[XLinkPos] == 9))
17363  {
17364  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17365  {
17366  for(int x = 0; x < VectorCount; x++)
17367  {
17368  SearchVector.erase(SearchVector.end() - 1);
17369  }
17370  Utilities->CallLogPop(2044);
17371  return(false);
17372  }
17373  }
17374  while(true)
17375  {
17376  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17377  {
17378  for(int x = 0; x < VectorCount; x++)
17379  {
17380  SearchVector.erase(SearchVector.end() - 1);
17381  }
17382  Utilities->CallLogPop(1927);
17383  return(false);
17384  }
17385  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17386  {
17387  for(int x = 0; x < VectorCount; x++)
17388  {
17389  SearchVector.erase(SearchVector.end() - 1);
17390  }
17391  Utilities->CallLogPop(290);
17392  return(false);
17393  }
17394  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17395  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17396  TPrefDirElement SearchElement(NextTrackElement);
17397  SearchElement.TrackVectorPosition = NextPosition;
17398  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17399  SearchElement.ELinkPos = NextELinkPos;
17400  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17401  int NextXLinkPos;
17402  if(SearchElement.ELinkPos == 0)
17403  {
17404  NextXLinkPos = 1;
17405  }
17406  if(SearchElement.ELinkPos == 1)
17407  {
17408  NextXLinkPos = 0;
17409  }
17410  if(SearchElement.ELinkPos == 2)
17411  {
17412  NextXLinkPos = 3;
17413  }
17414  if(SearchElement.ELinkPos == 3)
17415  {
17416  NextXLinkPos = 2;
17417  }
17418  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17419  {
17420  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17421  // but may be buffers, continuation or gap
17422  SearchElement.XLinkPos = NextXLinkPos;
17423  }
17424 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17425 // can't set XLink or XLinkPos yet if the element is a leading point.
17426 
17427 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17428  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17429  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17430  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17431 
17432  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17433 */
17434  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17435  {
17436  for(unsigned int x = 0; x < SearchVector.size(); x++)
17437  {
17438  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17439  {
17440  for(int x = 0; x < VectorCount; x++)
17441  {
17442  SearchVector.erase(SearchVector.end() - 1);
17443  }
17444  Utilities->CallLogPop(2655);
17445  return(false);
17446  }
17447  }
17448  }
17449  else if(SearchElement.TrackType == Bridge)
17450  {
17451  for(unsigned int x = 0; x < SearchVector.size(); x++)
17452  {
17453  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17454  (SearchElement.ELink == SearchVector.at(x).ELink))
17455  {
17456  for(int x = 0; x < VectorCount; x++)
17457  {
17458  SearchVector.erase(SearchVector.end() - 1);
17459  }
17460  Utilities->CallLogPop(2656);
17461  return(false);
17462  }
17463  }
17464  }
17465 
17466 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17467  TAllRoutes::TRouteElementPair SecondPair;
17469  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17470  if(RoutePair.first > -1)
17471  {
17472  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17473  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17474  RoutePair.second).ELinkPos)))
17475  {
17476  // still OK if start of an expected route
17477  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17478  {
17479  for(int x = 0; x < VectorCount; x++)
17480  {
17481  SearchVector.erase(SearchVector.end() - 1);
17482  }
17483  Utilities->CallLogPop(292);
17484  return(false); // only allow for start of an expected route
17485  }
17486  }
17487  }
17488  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17489  {
17490  // OK if it's a bridge & routes on different tracks
17491  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17492  SecondPair.second).ELinkPos)))
17493  {
17494  // still OK if start of an expected route
17495  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17496  {
17497  for(int x = 0; x < VectorCount; x++)
17498  {
17499  SearchVector.erase(SearchVector.end() - 1);
17500  }
17501  Utilities->CallLogPop(293);
17502  return(false); // only allow for start of an expected route
17503  }
17504  }
17505  }
17506 // check if a train on element, unless a bridge & train on different track
17507 // OK of same train as start element - no, drop this
17508 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17509  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17510  {
17511  for(int x = 0; x < VectorCount; x++)
17512  {
17513  SearchVector.erase(SearchVector.end() - 1);
17514  }
17515  Utilities->CallLogPop(294);
17516  return(false);
17517  }
17518  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17519  {
17520  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17521  {
17522  for(int x = 0; x < VectorCount; x++)
17523  {
17524  SearchVector.erase(SearchVector.end() - 1);
17525  }
17526  Utilities->CallLogPop(295);
17527  return(false);
17528  }
17529  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17530  {
17531  for(int x = 0; x < VectorCount; x++)
17532  {
17533  SearchVector.erase(SearchVector.end() - 1);
17534  }
17535  Utilities->CallLogPop(296);
17536  return(false);
17537  }
17538  }
17539 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17540  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17541  {
17542  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17543  {
17544  for(int x = 0; x < VectorCount; x++)
17545  {
17546  SearchVector.erase(SearchVector.end() - 1);
17547  }
17548  Utilities->CallLogPop(297);
17549  return(false);
17550  }
17551  }
17552 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17553 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17554 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17556  {
17557  for(int x = 0; x < VectorCount; x++)
17558  {
17559  SearchVector.erase(SearchVector.end() - 1);
17560  }
17561  Utilities->CallLogPop(1689);
17562  return(false);
17563  }
17564 // check if found it
17565  if(SearchElement.TrackVectorPosition == RequiredPosition)
17566  {
17567  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17568  {
17569  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17570  {
17571  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17572  }
17573  else
17574  {
17575  SearchElement.XLinkPos = 1;
17576  }
17577 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17578  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17579  }
17580  SearchVector.push_back(SearchElement);
17581  VectorCount++; // not really needed but include for tidyness
17582  TotalSearchCount++;
17583  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17584  {
17585  for(int x = 0; x < VectorCount; x++)
17586  {
17587  SearchVector.erase(SearchVector.end() - 1);
17588  }
17589  Utilities->CallLogPop(2525);
17590  return(false);
17591  }
17592  Utilities->CallLogPop(298);
17593  return(true);
17594  }
17595 // Not the required element - check if a buffer or continuation
17596  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17597  {
17598  for(int x = 0; x < VectorCount; x++)
17599  {
17600  SearchVector.erase(SearchVector.end() - 1);
17601  }
17602  Utilities->CallLogPop(299);
17603  return(false);
17604  }
17605 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17607  {
17608  for(int x = 0; x < VectorCount; x++)
17609  {
17610  SearchVector.erase(SearchVector.end() - 1);
17611  }
17612  Utilities->CallLogPop(1421);
17613  return(false);
17614  }
17615 //deal with failed points, added at v2.13.0
17616  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17617  {
17618  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17619  {
17620  SearchElement.XLinkPos = 1;
17621  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17622  }
17623  else
17624  {
17625  SearchElement.XLinkPos = 3;
17626  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17627  }
17628  }
17629  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17630  {
17631  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17632  {
17633  for(int x = 0; x < VectorCount; x++)
17634  {
17635  SearchVector.erase(SearchVector.end() - 1);
17636  }
17637  Utilities->CallLogPop(2533);
17638  return(false);
17639  }
17640  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17641  {
17642  for(int x = 0; x < VectorCount; x++)
17643  {
17644  SearchVector.erase(SearchVector.end() - 1);
17645  }
17646  Utilities->CallLogPop(2534);
17647  return(false);
17648  }
17649  }
17650 
17651 // check if reached a non-failed leading point
17652  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17653  { //added !Failed condition at v2.13.0 to exclude failed points
17654 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17655  int SearchPos1 = SearchElement.Attribute + 1;
17656  int SearchPos2;
17657  if(SearchPos1 == 2)
17658  {
17659  SearchPos1++;
17660  }
17661  if(SearchPos1 == 1)
17662  {
17663  SearchPos2 = 3;
17664  }
17665  else
17666  {
17667  SearchPos2 = 1;
17668  }
17669 // push element with XLink set to position [SearchPos1]
17670  SearchElement.XLink = SearchElement.Link[SearchPos1];
17671  SearchElement.XLinkPos = SearchPos1;
17672 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17673  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17674  {
17675  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17676  {
17677  for(int x = 0; x < VectorCount; x++)
17678  {
17679  SearchVector.erase(SearchVector.end() - 1);
17680  }
17681  Utilities->CallLogPop(300);
17682  return(false);
17683  }
17684  }
17685  SearchVector.push_back(SearchElement);
17686  VectorCount++;
17687  TotalSearchCount++;
17688 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17689 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17690 // recursive search as has to be a TTrackElement for non-preferred route searches
17691  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17692  {
17693  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17694  {
17695  for(int x = 0; x < VectorCount; x++)
17696  {
17697  SearchVector.erase(SearchVector.end() - 1);
17698  }
17699  Utilities->CallLogPop(2526);
17700  return(false);
17701  }
17702  Utilities->CallLogPop(301);
17703  return(true);
17704  }
17705  else
17706  {
17707 // remove leading point with XLinkPos [SearchPos1]
17708  SearchVector.erase(SearchVector.end() - 1);
17709  VectorCount--;
17710 // push element with XLink set to position [SearchPos2]
17711  SearchElement.XLink = SearchElement.Link[SearchPos2];
17712  SearchElement.XLinkPos = SearchPos2;
17713 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17714  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17715  {
17716  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17717  {
17718  for(int x = 0; x < VectorCount; x++)
17719  {
17720  SearchVector.erase(SearchVector.end() - 1);
17721  }
17722  Utilities->CallLogPop(302);
17723  return(false);
17724  }
17725  }
17726  SearchVector.push_back(SearchElement);
17727  VectorCount++;
17728  TotalSearchCount++;
17729 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17730  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17731  {
17732  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17733  {
17734  for(int x = 0; x < VectorCount; x++)
17735  {
17736  SearchVector.erase(SearchVector.end() - 1);
17737  }
17738  Utilities->CallLogPop(2527);
17739  return(false);
17740  }
17741  Utilities->CallLogPop(303);
17742  return(true);
17743  }
17744  else
17745  {
17746  for(int x = 0; x < VectorCount; x++)
17747  {
17748  SearchVector.erase(SearchVector.end() - 1);
17749  }
17750  Utilities->CallLogPop(304);
17751  return(false);
17752  }
17753  }
17754  } // if leading point
17755 
17756 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17757 // ready for next element on route
17758  SearchVector.push_back(SearchElement);
17759  VectorCount++;
17760  TotalSearchCount++;
17761  CurrentTrackElement = SearchElement;
17762  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17763  } // while(true)
17764 }
17765 
17766 // ---------------------------------------------------------------------------
17767 
17769 
17770 /*
17771  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17772  having all values set (since not necessarily on PrefDirs).
17773  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17774  (if it was the start), so these are checked first and set if necessary. All elements now have
17775  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17776  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17777  to set the route colour and direction graphics.
17778 */
17779 
17780 {
17781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17782  if(SearchVector.size() == 0)
17783  {
17784  throw Exception("Error, SearchVector empty");
17785  }
17786 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17787 // hence need to examine and update it if necessary
17788  TPrefDirElement SecondElement;
17789 
17790  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17791  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17792  // need above check or SecondElement will fail
17793  {
17794  SecondElement = SearchVector.at(1);
17795  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17796  for(int x = 0; x < 4; x++)
17797  {
17798  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17799  {
17800  if(SearchVector.at(0).XLink == -1) // i.e. not set
17801  {
17802  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17803  SearchVector.at(0).XLinkPos = x;
17804  }
17805  int ELinkPos;
17806  if(SearchVector.at(0).XLinkPos == 0)
17807  {
17808  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17809  }
17810  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17811  if(SearchVector.at(0).XLinkPos == 1)
17812  {
17813  ELinkPos = 0;
17814  }
17815  if(SearchVector.at(0).XLinkPos == 2)
17816  {
17817  ELinkPos = 3;
17818  }
17819  if(SearchVector.at(0).XLinkPos == 3)
17820  {
17821  ELinkPos = 2;
17822  }
17823  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17824  {
17825  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17826  SearchVector.at(0).ELinkPos = ELinkPos;
17827  }
17828  break; // no point going any further
17829  }
17830  }
17831  }
17832  for(unsigned int x = 0; x < SearchVector.size(); x++)
17833  {
17834  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17835 // set EXNumber
17836  if(!(SearchVector.at(x).EntryExitNumber()))
17837  {
17838  throw Exception("Error in EntryExitNumber 3");
17839  }
17840  SearchVector.at(x).CheckCount++;
17841 // all values now incorporated
17842  }
17843 
17844  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17845 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17846 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17847  Utilities->CallLogPop(305);
17848 }
17849 
17850 // ---------------------------------------------------------------------------
17851 
17853 
17854 /*
17855  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17856  AutoSigsRoute.
17857  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17858  beginning or the end.
17859  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17860  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17861  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17862  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17863  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17864  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17865  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17866 
17867  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17868  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17869  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17870  route at the start.
17871 
17872  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17873  for the new route and return.
17874 */
17875 
17876 {
17877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17878  AnsiString(ReqPosRouteID.GetInt()));
17879  if(SearchVector.size() < 1)
17880  {
17881  Utilities->CallLogPop(306);
17882  return;
17883  }
17884  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17885  if(!ValidatePrefDir(6))
17886  {
17887  Utilities->CallLogPop(307);
17888  return;
17889  }
17890  TAllRoutes::TLockedRouteClass LockedRouteObject;
17891 
17893  unsigned int TruncatePrefDirPosition = 0;
17894 
17895  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17896 /* if have ReqPosRouteID:
17897  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17898  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17899  then enter the new route into the AllRoutesVector
17900 */
17901  {
17903  {
17904  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17905  x++) // start at 1 as first element already in SearchVector
17906  {
17908  }
17909  // note that route numbers in map adjusted when ReqPos route cleared
17911  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17912  // set during ClearRouteDuringRouteBuildingAt)
17914  {
17917  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17918  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17919  }
17920  }
17922  {
17923  SearchVector.pop_back();
17924  }
17925  }
17926  if(StartSelectionRouteID > -1)
17927 /* if have StartSelectionRouteID:
17928  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17929  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17930 */
17931  {
17933  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17934  {
17936  {
17937  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17938  for(unsigned int x = 0; x < SearchVector.size(); x++)
17939  {
17941  RouteNumber, GetFixedSearchElementAt(7, x));
17942  // find & store locked route truncate position in PrefDirVector for later use
17944  {
17945  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17946  {
17947  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17948  }
17949  }
17950  }
17952  {
17953  throw Exception("Failed to validate extended route for nonpreferred route");
17954  }
17957  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17958  // now add the reinstated locked route if required and set signals accordingly
17959  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17960  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17961  // that I haven't thought of
17963  {
17964  LockedRouteObject.RouteNumber = RouteNumber;
17965  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17966  // now reset the signals for the locked route
17967  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17968  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17969  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17970  {
17971  // return all signals to red in route section to be truncated
17972  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17973  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17974  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17975  {
17976  TrackElement.Attribute = 0;
17977  Track->PlotSignal(11, TrackElement, Display);
17978  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17979  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17980  }
17981  }
17982  }
17983  AllRoutes->CheckMapAndRoutes(3); // test
17984  Utilities->CallLogPop(308);
17985  return;
17986  }
17987  }
17988  else
17989  {
17991  }
17992 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17993 // hence nothing to do here
17994  }
17995  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17996  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17997  {
17998  throw Exception("Failed to validate single route for nonpreferred route");
17999  }
18000  AllRoutes->StoreOneRoute(2, this);
18001  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
18002  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18003  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18004  AllRoutes->CheckMapAndRoutes(4); // test
18005  Utilities->CallLogPop(309);
18006 }
18007 
18008 // ---------------------------------------------------------------------------
18009 
18010 void TOneRoute::SetRoutePoints(int Caller) const
18011 /*
18012  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18013  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18014  when they were created.
18015 */
18016 {
18017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18018  if(!PrefDirVector.empty())
18019  {
18020  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18021  {
18022  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18023  {
18024  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18025  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18026  }
18027  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18028  {
18029  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18030  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18031  }
18032  }
18033  }
18034  Utilities->CallLogPop(327);
18035 }
18036 
18037 // ---------------------------------------------------------------------------
18038 
18039 void TOneRoute::SetRouteSignals(int Caller) const
18040 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18041 
18042 {
18043  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18044  if(!PrefDirVector.empty())
18045  {
18046  int RouteNumber;
18047  int Attribute = 0;
18048  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18049  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18050  if(RouteType != TAllRoutes::NoRoute)
18051  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18052  {
18053  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18054  }
18055  }
18056  Utilities->CallLogPop(1720);
18057 }
18058 
18059 // ---------------------------------------------------------------------------
18060 
18061 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18062 {
18063  //true if at any point in SearchVector points have to be changed,
18064  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18066  NewFailedPointsTVPos = -1; //default value for no new failure
18067  bool PointsChanged = false;
18068  if(!SearchVector.empty())
18069  {
18070  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18071  {
18072  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18073  //check for an existing failed point where needs to change to make the route
18074  int Attr = TE.Attribute;
18075  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18076  {
18077  if(Attr == 1) //currently set to diverge
18078  {
18079  //here add new failure possibility at v2.13.0
18080  if(Utilities->FailureMode != FNil)
18081  {
18082  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18083  {
18085  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18086  IFE.TVPos = NewFailedPointsTVPos;
18087  TE.Failed = true;
18088  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18090  TE.SpeedLimit01 = 10; //values while failed
18091  TE.SpeedLimit23 = 10;
18092  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18093  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18094  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18095  //set repair time, random value in minutes between 10 and 179
18096  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18097  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18098  IFE.RepairTime = RepairTime;
18100  Track->FailedPointsVector.push_back(IFE);
18101  Utilities->CallLogPop(1717);
18102  return(true); //return so only allow one failure per route
18103  }
18104  }
18105  PointsChanged = true; //this is used for setting the flash time
18106  }
18107  }
18108  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18109  {
18110  if(Attr == 0) //currently set to go straight
18111  {
18112  //here add failure possibility at v2.13.0
18113  if(Utilities->FailureMode != FNil)
18114  {
18115  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18116  {
18118  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18119  IFE.TVPos = NewFailedPointsTVPos;
18120  TE.Failed= true;
18121  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18123  TE.SpeedLimit01 = 10; //values while failed
18124  TE.SpeedLimit23 = 10;
18125  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18126  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18127  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18128  //set repair time, random value in minutes between 10 and 179
18129  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18130  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18131  IFE.RepairTime = RepairTime;
18133  Track->FailedPointsVector.push_back(IFE);
18134  Utilities->CallLogPop(1718);
18135  return(true); //only allow one failure per route
18136  }
18137  }
18138  PointsChanged = true;
18139  }
18140  }
18141  }
18142  }
18143  Utilities->CallLogPop(1719);
18144  return(PointsChanged);
18145 }
18146 
18147 // ---------------------------------------------------------------------------
18148 
18149 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18150 /* //added StartPos at v2.17.0 so it starts in the current route
18151 
18152  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18153 
18154  Works forward through the route from & including StartPos until finds:-
18155  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18156  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18157  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18158  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18159  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18160  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18161  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18162  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18163  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18164 */
18165 {
18166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18167  Attribute = 0;
18168  NextForwardLinkedRouteNumber = -1;
18169  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18170  {
18171  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18172  if(PrefDirVector.at(x).TrackType == Bridge)
18173  {
18174  if(PrefDirVector.at(x).XLinkPos < 2)
18175  {
18176  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18177  }
18178  else
18179  {
18180  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18181  }
18182  }
18183  if(TrainID != -1)
18184  {
18185  Utilities->CallLogPop(328); //attribute still 0
18186  return(true);
18187  }
18188  if(PrefDirVector.at(x).TrackType == Buffers)
18189  {
18190  Attribute = 1;
18191  Utilities->CallLogPop(329);
18192  return(true);
18193  }
18194  if(PrefDirVector.at(x).TrackType == Continuation)
18195  {
18196  Attribute = 3;
18197  Utilities->CallLogPop(330);
18198  return(true);
18199  }
18200  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18201  {
18202  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18203  {
18204  Attribute = 0;
18205  Utilities->CallLogPop(1950);
18206  return(true);
18207  }
18208  }
18209  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18210  {
18211  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18212  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18213  {
18214  Attribute++;
18215  }
18216  if(Attribute > 3)
18217  {
18218  Attribute = 3;
18219  }
18220  Utilities->CallLogPop(331);
18221  return(true);
18222  }
18223  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18224  {
18225  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18226  NextForwardLinkedRouteNumber = -1;
18227  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18228 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18229  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18230  {
18231  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18232  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18233  {
18234  Attribute = 0;
18235  Utilities->CallLogPop(332);
18236  return(false);
18237  }
18238  //else there is no forward route, so return true with attribute still 0
18239  }
18240  //else there is no forward route, so return true with attribute still 0
18241  }
18242  }
18243  Utilities->CallLogPop(333); //
18244  return(true);
18245 }
18246 
18247 // ---------------------------------------------------------------------------
18248 
18249 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18250 /* Major changes at v2.17.0
18251  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18252 
18253  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18254  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18255  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18256  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18257  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18258  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18259  or (c) truncating a route.
18260 
18261  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18262  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18263  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18264  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18265  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18266  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18267  the function returns true.
18268 
18269  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18270  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18271 */
18272 {
18273  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18274  AnsiString(PrefDirVectorStartPosition));
18275  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18276  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18277 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18278 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18279 
18280  if(!PrefDirVector.empty())
18281  {
18282  if(!SkipForwardLook)
18283  {
18284  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18285  {
18286  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18287  if(PrefDirPtr->TrackType == Bridge)
18288  {
18289  if(PrefDirPtr->XLinkPos < 2)
18290  {
18291  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18292  }
18293  else
18294  {
18295  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18296  }
18297  }
18298  if(TrainID != -1)
18299  {
18300  SkipForwardLook = true;
18301  break;
18302  }
18303  }
18304  }
18305 
18307  {
18308  SkipForwardLook = true;
18309  }
18310 
18311  int NextForwardLinkedRouteNumber = -1;
18312  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18313  {
18314  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18316 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18317  if(RouteType == TAllRoutes::NoRoute)
18318  {
18319  SkipForwardLook = true; //if there's no linked forward route then skip
18320  if(PrefDirVector.back().TrackType == Buffers)
18321  {
18322  Attribute = 1; // treat buffer as red signal
18323  }
18324  if(PrefDirVector.back().TrackType == Continuation)
18325  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18326  bool SetAttributeTo3 = true;
18329  {
18330  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18331  AutoSigVectorIT++)
18332  {
18333  if(!AllRoutes->AllRoutesVector.empty())
18334  {
18335  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18336  {
18337  SetAttributeTo3 = false;
18338  Attribute = AutoSigVectorIT->AccessNumber;
18339  break;
18340  }
18341  }
18342  }
18343  }
18344  if(SetAttributeTo3)
18345  {
18346  Attribute = 3; // treat continuation as a green signal
18347  }
18348  }
18349  }
18350  else //startpos still on end element and there is probably a forward route
18351  {
18352  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18353  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18354  {
18355  SkipForwardLook = true; //if there's no linked forward route then skip
18356  if(PrefDirVector.back().TrackType == Buffers)
18357  {
18358  Attribute = 1; // treat buffer as red signal
18359  }
18360  if(PrefDirVector.back().TrackType == Continuation)
18361  {
18362  Attribute = 3; // treat continuation as a green signal
18363  }
18364  }
18365  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18366  }
18367  }
18368 
18369  if(!SkipForwardLook)
18370  {
18371  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18372  //SkipForwardLook will be true - see above)
18373  int StartPos;
18374  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18375  {
18376  StartPos = PrefDirVectorStartPosition + 1;
18377  }
18378  else
18379  {
18380  StartPos = 0; //start of next forward route
18381  }
18382  if(StartPos > 0) //starting in this route
18383  {
18384  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18385  {
18386  StartPos = 0; //reset to 0 for next route
18387  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18388  {
18389  continue;
18390  }
18391  }
18392  }
18393  else //starting in next forward route
18394  {
18395  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18396  {
18397  continue;
18398  }
18399  }
18400  }
18401 
18402  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18403  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18404  {
18405  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18406  if(PrefDirPtr->TrackType == Bridge)
18407  {
18408  if(PrefDirPtr->XLinkPos < 2)
18409  {
18410  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18411  }
18412  else
18413  {
18414  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18415  }
18416  }
18417  if(TrainID != -1)
18418  {
18419  Utilities->CallLogPop(334);
18420  return(false);
18421  }
18422  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18423  // the attribute to 0 so first signal behind the LC is red
18424  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18425  {
18426  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18427  {
18428  Attribute = 0;
18429  }
18430  }
18431 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18432 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18433  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18434  {
18435  if((!AllRoutes->RouteBackTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18436  PrefDirPtr->PrefDirRoute)
18437  {
18438 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18439 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18440  int LockedVecNum = 0; //not used
18441  TPrefDirElement DummyPrefDir; //not used
18442  bool KeepAttributeAt0ForLockedRoute = false;
18443  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18444  LockedVecNum))
18445  {
18446  Attribute = 0;
18447  KeepAttributeAt0ForLockedRoute = true;
18448  }
18449 //end of v2.9.2 addition
18450 
18451 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18452  bool NotGroundSignal = false;
18453  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18454  {
18455  NotGroundSignal = true;
18456  }
18457 
18458  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18459  {
18460  Attribute = 0; //stays at 0
18461  }
18462 
18463  if(Attribute < 3)
18464  {
18465  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18466  }
18467  else
18468  {
18469  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18470  }
18471  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18472  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18473  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18474  {
18475  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18476  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18477  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18478  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18479  }
18480  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18481  { //if groundsignal attrib is 0 then do need to increment
18482  Attribute++; //this is for the next signal rearwards, not the current one
18483  }
18484 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18485  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18486  }
18487  }
18488  }
18489  }
18490  Utilities->CallLogPop(335);
18491  return(true);
18492 }
18493 
18494 // ---------------------------------------------------------------------------
18495 
18496 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18497 /*
18498  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18499  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18500  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18501  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18502  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18503  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18504  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18505  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18506 */
18507 {
18508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18509  "," + AnsiString((short)PrefDirRoute));
18510  bool ElementInRoute = false;
18511  bool MovingTrainOccupyingRoute = false;
18512  unsigned int TruncatePDElementPos; //the selected PD position to truncate to (could be from the back or the front)//added at v2.15.0
18513  enum {NoTruncate, BackTruncate, FrontTruncate, FullTruncate} TruncateType;
18514  TruncateType = NoTruncate;
18516 
18517  for(unsigned int b = 0; b < PrefDirSize(); b++)
18518  {
18519  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18520  {
18521  TruncatePDElementPos = b;
18522  ElementInRoute = true;
18523  break;
18524  }
18525  }
18526  if(!ElementInRoute)
18527  {
18528  ReturnFlag = NotInRoute;
18529  Utilities->CallLogPop(336);
18530  return;
18531  }
18532 
18533  //now find whether back, front or full truncate //added at v2.15.0
18534  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate
18535  {
18536  if(TruncatePDElementPos == 0)
18537  {
18538  TruncateType = FullTruncate;
18539  AllRoutes->RouteBackTruncateFlag = true; //Added at v2.15.1: FullTruncate is also a form of BackTruncate as far as the flag is concerned for SetAllRearwardsSignals
18540  } //without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18541  else //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18542  { //truncate for that route), the last signal in the autosigs route doesn't change to red.
18543  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18544  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18545  {
18546  TruncateType = FrontTruncate;
18547  }
18548  else
18549  {
18550  TruncateType = BackTruncate;
18552  }
18553  }
18554  }
18555  else // == PrefDirSize() - 1
18556  {
18557  TruncateType = BackTruncate;
18559  }
18560 
18561 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
18562 
18563  if(TruncateType == BackTruncate) //added at v2.15.0
18564  {
18565  for(int b = PrefDirSize() - 1; b >= 0; b--)
18566  {
18567  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18568  if(PrefDirVector.at(b).TrackType == Bridge)
18569  {
18570  if(PrefDirVector.at(b).XLinkPos < 2)
18571  {
18572  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18573  }
18574  else
18575  {
18576  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18577  }
18578  }
18579  if(TrainID != -1)
18580  {
18581  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18582  {
18583  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18584  }
18585  }
18586  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18587  {
18588  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18589  ReturnFlag = InRouteFalse;
18591  Utilities->CallLogPop(1941);
18592  return;
18593  }
18594  if(b == int(TruncatePDElementPos))
18595  {
18596  break; // OK found truncate element & no flashing LC in front
18597  }
18598  }
18599  }
18600  else if(TruncateType == FrontTruncate)//front/full truncate //added at v2.15.0
18601  {
18602  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
18603  {
18604  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18605  if(PrefDirVector.at(b).TrackType == Bridge)
18606  {
18607  if(PrefDirVector.at(b).XLinkPos < 2)
18608  {
18609  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18610  }
18611  else
18612  {
18613  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18614  }
18615  }
18616  if(TrainID != -1)
18617  {
18618  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
18619  {
18620  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18621  }
18622  }
18623  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18624  {
18625  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
18626  ReturnFlag = InRouteFalse;
18628  Utilities->CallLogPop(2571);
18629  return;
18630  }
18631  if(b == TruncatePDElementPos)
18632  {
18633  break; // OK found truncate element & no flashing LC behind
18634  }
18635  }
18636  }
18637  else //FullTruncate) //added at v2.15.0
18638  {
18639  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
18640  {
18641  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18642  if(PrefDirVector.at(b).TrackType == Bridge)
18643  {
18644  if(PrefDirVector.at(b).XLinkPos < 2)
18645  {
18646  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18647  }
18648  else
18649  {
18650  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18651  }
18652  }
18653  if(TrainID != -1)
18654  {
18655  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
18656  {
18657  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18658  }
18659  }
18660  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18661  {
18662  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
18663  ReturnFlag = InRouteFalse;
18665  Utilities->CallLogPop(2572);
18666  return;
18667  }
18668  }
18669  }
18670 
18671  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
18672  {
18673  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
18674  ReturnFlag = InRouteFalse;
18676  Utilities->CallLogPop(338);
18677  return;
18678  }
18679  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
18680  {
18681  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
18682  ReturnFlag = InRouteFalse;
18684  Utilities->CallLogPop(339);
18685  return;
18686  }
18687 
18688  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
18689  {
18690  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
18691  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18692  {
18693  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18694  {
18695  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18696  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18697  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18698  ReturnFlag = InRouteFalse;
18700  Utilities->CallLogPop(340);
18701  return;
18702  }
18703  }
18704  else
18705  {
18706  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18707  {
18708  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
18709  ReturnFlag = InRouteFalse;
18711  Utilities->CallLogPop(341);
18712  return;
18713  }
18714  }
18715  }
18716 
18717  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
18718  {
18719  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
18720  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18721  {
18722  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18723  {
18724  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18725  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18726  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18727  ReturnFlag = InRouteFalse;
18729  Utilities->CallLogPop(2573);
18730  return;
18731  }
18732  }
18733  else //red route
18734  {
18735  if(TruncatePDElementPos > 0)
18736  {
18737  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
18738  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18739  {
18740  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
18741  ReturnFlag = InRouteFalse;
18743  Utilities->CallLogPop(2574);
18744  return;
18745  }
18746  }
18747  }
18748  }
18749 
18750  else if(TruncatePDElementPos == 0) //full truncate
18751  {
18752  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
18753  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
18754  {
18755  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
18756  {
18757  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18758  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18759  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18760  ReturnFlag = InRouteFalse;
18762  Utilities->CallLogPop(2575);
18763  return;
18764  }
18765  }
18766  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
18767  {
18768  if(TempElement.TrackType == Bridge)
18769  {
18770  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
18771  ReturnFlag = InRouteFalse;
18773  Utilities->CallLogPop(2576);
18774  return;
18775  }
18776  }
18777  }
18778 
18779  int ThisRouteNumber;
18781 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
18782 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
18783 
18784 // check if part of this route already locked & disallow if so
18785  if(!(AllRoutes->LockedRouteVector.empty()))
18786  {
18788  {
18789  if(LRVIT->RouteNumber == ThisRouteNumber)
18790  {
18791  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
18792  ReturnFlag = InRouteFalse;
18794  Utilities->CallLogPop(749);
18795  return;
18796  }
18797  }
18798  }
18799 
18800  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
18801  if(TruncateType == BackTruncate) //is within 3 running signals on this or linked rearwards routes -m this is a PDElement position
18802  {
18803  LookBackwardsFromHere = TruncatePDElementPos;
18804  }
18805 
18806 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
18807  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
18808  int FrontPosition;
18809 
18810  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
18811  // RouteLockingRequired only checks for trains approaching
18812  {
18815  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
18816  L"Warning!", MB_YESNO | MB_ICONWARNING);
18817  TrainController->BaseTime = TDateTime::CurrentDateTime();
18819  if(button == IDNO)
18820  {
18821  ReturnFlag = InRouteTrue; // still return true even though don't act on it
18823  Utilities->CallLogPop(342);
18824  return;
18825  }
18826  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
18827  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
18828  TAllRoutes::TLockedRouteClass LockedRoute;
18829  bool ExistingLockedRouteModified = false;
18830  LockedRoute.RouteNumber = ThisRouteNumber;
18831  if(TruncateType == BackTruncate)
18832  {
18833  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18834  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18835  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18836  }
18837  else if(TruncateType == FrontTruncate)
18838  {
18839  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18840  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18841  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
18842  }
18843  else //FullTruncate
18844  {
18845  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18846  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18847  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18848  }
18849 
18850  LockedRoute.LockStartTime = TrainController->TTClockTime;
18851 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
18852 // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
18853  if(!AllRoutes->LockedRouteVector.empty())
18854  {
18855  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
18856  LRVIT++)
18857  {
18858  if(LRVIT->RouteNumber == ThisRouteNumber)
18859  {
18860  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
18861  LRVIT->LockStartTime = LockedRoute.LockStartTime;
18862  ExistingLockedRouteModified = true;
18863  }
18864  }
18865  }
18866  if(!ExistingLockedRouteModified)
18867  {
18868  AllRoutes->LockedRouteVector.push_back(LockedRoute);
18869  }
18870  if(TruncateType == BackTruncate)
18871  {
18872  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
18873  RearPosition = TruncatePDElementPos;
18874  FrontPosition = PrefDirSize() - 1;
18875  }
18876  else if(TruncateType == FrontTruncate)
18877  {
18878  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
18879  RearPosition = 0;
18880  FrontPosition = TruncatePDElementPos;
18881  }
18882  else //FullTruncate
18883  {
18884  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
18885  RearPosition = 0;
18886  FrontPosition = PrefDirSize() - 1;
18887  }
18888 // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
18889  for(int c = FrontPosition; c >= RearPosition; c--)
18890  {
18891  // return all signals to red in route section to be truncated
18892  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
18893  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
18894  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18895  {
18896  TrackElement.Attribute = 0;
18897  Track->PlotSignal(2, TrackElement, Display);
18898  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18899  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18900  }
18901  }
18902 // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
18903  ReturnFlag = InRouteTrue;
18904  }
18905  else //route locking not required
18906  {
18907  if(TruncateType == BackTruncate)
18908  {
18909  RearPosition = TruncatePDElementPos;
18910  FrontPosition = PrefDirSize() - 1;
18911  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
18912  }
18913  else if(TruncateType == FrontTruncate)
18914  {
18915  RearPosition = 0;
18916  FrontPosition = TruncatePDElementPos;
18917  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
18918  }
18919  else
18920  {
18921  RearPosition = 0;
18922  FrontPosition = PrefDirSize() - 1;
18923  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
18924  }
18925 
18926  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
18927  //into adjacent red or green routes if there are any (after the truncation/removal)
18928 
18929  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18930  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
18931 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
18932 
18933  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
18934  {
18935  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
18936  ReturnFlag = InRouteTrue;
18937  }
18938 
18939  if(LastPDElement.AutoSignals)
18940  {
18941  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
18942  }
18943  }
18944 
18945  AllRoutes->CheckMapAndRoutes(5); // test
18946  ReturnFlag = InRouteTrue;
18948  Utilities->CallLogPop(344);
18949 }
18950 
18951 // ---------------------------------------------------------------------------
18952 
18954 {
18955 /*
18956 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
18957 signal.
18958 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
18959  but a new route that is created TO a signal - that signal becomes part of the new route.
18960 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
18961 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
18962  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
18963  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
18964  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
18965  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
18966  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
18967 */
18968 
18969  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
18970  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
18971  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
18972  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
18973  {
18974  Utilities->CallLogPop(2578);
18975  return;
18976  }
18977  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
18978  int RouteColour;
18979  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
18980  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18981  {
18982  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
18983  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
18984  { //found a linked forward route
18985  //check if signal behind this route has been removed from the blue route
18986  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18987  { //signal needs to be added at start of this linked route
18988 
18989  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
18990  if(RouteColour == 1) //red route
18991  {
18992  NewRedFirstPDElement = LastPDElement;
18993  NewRedFirstPDElement.AutoSignals = false;
18994  NewRedFirstPDElement.PrefDirRoute = false;
18995  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18996  NewRedFirstPDElement.IsARoute = true;
18997  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
18998  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
18999  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19000  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19001  {
19002  if(R2MMIt->second.first == int(x))
19003  {
19004  R2MMIt->second.second++;
19005  }
19006  }
19007  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19008  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19009  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19010  }
19011  else if(RouteColour == 2) //green route
19012  {
19013  NewGreenFirstPDElement = LastPDElement;
19014  NewGreenFirstPDElement.AutoSignals = false;
19015  NewGreenFirstPDElement.PrefDirRoute = true;
19016  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19017  NewGreenFirstPDElement.IsARoute = true;
19018  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19019  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19020  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19021  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19022  {
19023  if(R2MMIt->second.first == int(x))
19024  {
19025  R2MMIt->second.second++;
19026  }
19027  }
19028  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19029  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19030  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19031  }
19032  }
19033  break; //no point looking any further
19034  }
19035  }
19036 
19037 //check if there's a linked rearward route missing a signal and if so add it
19038  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19039  {
19040  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19041  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19042  { //found a linked rearward route
19043  //check if signal in front of this route has been removed from the blue route
19044  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19045  { //signal needs to be added at end of this linked route
19046 
19047  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19048  if(RouteColour == 1) //red route
19049  {
19050  NewRedLastPDElement = FirstPDElement;
19051  NewRedLastPDElement.AutoSignals = false;
19052  NewRedLastPDElement.PrefDirRoute = false;
19053  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19054  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19055  //can use this as adding to the end of the route
19056  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19057  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19058  }
19059  else if(RouteColour == 2) //green route
19060  {
19061  NewGreenLastPDElement = FirstPDElement;
19062  NewGreenLastPDElement.AutoSignals = false;
19063  NewGreenLastPDElement.PrefDirRoute = true;
19064  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19065  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19066  //can use this as adding to the end of the route
19067  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19068  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19069  }
19070  }
19071  break; //no point looking any further
19072  }
19073  }
19074  Utilities->CallLogPop(2579);
19075 }
19076 
19077 // ---------------------------------------------------------------------------
19078 
19080 /*
19081  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19082  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19083  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19084  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19085  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19086  the route colours.
19087 */
19088 {
19089  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19090  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19092  int RouteNumber;
19093  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19094  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19095  //these added at v2.15.0
19096  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19097  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19098 
19099  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19100  {
19101  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19102  {
19103  if(PrefDirVector.at(x).TrackType == SignalPost)
19104  {
19105  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19106  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19107  }
19108  }
19109 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19110  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19111  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19112  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19113  //when should have been be red.
19114 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19115  }
19116  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19117  {
19118  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19119  }
19120 
19121  if(LastPDElement.AutoSignals) //added at v2.15.0
19122  {
19123  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19124  }
19125 
19126  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19127  {
19128  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19129  {
19130  ARVIt->SetRouteSignals(14);
19131  }
19132  }
19133  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19134  AllRoutes->CheckMapAndRoutes(9); // test
19135  TrainController->BaseTime = TDateTime::CurrentDateTime();
19137  Utilities->CallLogPop(345);
19138  return;
19139 }
19140 
19141 // ---------------------------------------------------------------------------
19142 
19143 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19144 /*
19145  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19146 */
19147 {
19148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19149  AnsiString((short)PrefDirRoute));
19150  if(SearchVector.empty())
19151  {
19152  Utilities->CallLogPop(1149);
19153  return;
19154  }
19155  for(unsigned int b = 0; b < SearchVector.size(); b++)
19156  {
19159  PrefDirRoute);
19160  }
19161  Utilities->CallLogPop(346);
19162 }
19163 
19164 // ---------------------------------------------------------------------------
19165 
19166 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19167 /*
19168  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19169  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19170  TOneRoute.
19171 */
19172 {
19173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19174  AnsiString((short)PrefDirRoute));
19175  RouteFlash.RouteFlashVector.clear();
19176  TRouteFlashElement RouteFlashElement;
19177 
19178  for(unsigned int b = 0; b < SearchVector.size(); b++)
19179  {
19180  int H = GetFixedSearchElementAt(11, b).HLoc;
19181  int V = GetFixedSearchElementAt(12, b).VLoc;
19183  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19184  RouteFlashElement.HLoc = H;
19185  RouteFlashElement.VLoc = V;
19187  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19188  }
19189  Utilities->CallLogPop(348);
19190 }
19191 
19192 // ---------------------------------------------------------------------------
19193 
19194 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19195 {
19196  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19197  if(!PrefDirVector.empty())
19198  {
19199  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19200  {
19201  int H = PrefDirPtr->HLoc;
19202  int V = PrefDirPtr->VLoc;
19203  // check for any LCs that are closed to trains & set the flash values and store in the vector
19204  if(Track->IsLCAtHV(39, H, V))
19205  {
19206  if(Track->IsLCBarrierUpAtHV(0, H, V))
19207  {
19208  Track->LCChangeFlag = true;
19209  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19210  CLC.HLoc = H;
19211  CLC.VLoc = V;
19213  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19216  if(PrefDirRoute)
19217  {
19218  CLC.TypeOfRoute = 1;
19219  }
19220  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19221  Track->ChangingLCVector.push_back(CLC);
19222  }
19223  }
19224  }
19225  }
19226  Utilities->CallLogPop(1948);
19227 }
19228 
19229 // ---------------------------------------------------------------------------
19230 
19232 /*
19233  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19234  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19235  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19236  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19237 */
19238 {
19239  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19240  if(!OverlayPlotted)
19241  {
19242  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19243  {
19244  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19245  {
19246  continue;
19247  }
19248  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19249  Display->Update();
19250  }
19251  OverlayPlotted = true;
19252  }
19253  Utilities->CallLogPop(349);
19254 }
19255 
19256 // ---------------------------------------------------------------------------
19257 
19259 /*
19260  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19261  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19262  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19263  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19264 */
19265 {
19266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19267  if(OverlayPlotted)
19268  {
19269  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19270  {
19271  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19272  {
19273  continue;
19274  }
19275  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19276  Display->Update();
19277  }
19278  OverlayPlotted = false;
19279  }
19280  Utilities->CallLogPop(350);
19281 }
19282 
19283 // ---------------------------------------------------------------------------
19284 
19285 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19286 {
19287 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19288 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19289 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19290 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19291 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19292 messages, and allocate a repair time similar to points)
19293 */
19294 
19295  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19296  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19297  {
19298  Utilities->CallLogPop(2528);
19299  return(false);
19300  }
19301  bool FirstSignalFound = false;
19302  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19303  {
19304  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19305 //check for a failed point where needs to change to make the route
19306 //shouldn't be any but check to be safe
19307  int Attr = TE.Attribute;
19308  if(PDVIt->TrackType == Points)
19309  {
19310  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19311  {
19312  if(Attr == 1) //currently set to diverge
19313  {
19314  if(TE.Failed)
19315  {
19316  Utilities->CallLogPop(2529);
19317  return(false); //return without further checking
19318  }
19319  }
19320  }
19321  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19322  {
19323  if(Attr == 0) //currently set to go straight
19324  {
19325  if(TE.Failed)
19326  {
19327  Utilities->CallLogPop(2530);
19328  return(false); //return without further checking
19329  }
19330  }
19331  }
19332  }
19333  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19334  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19335  //the search vector)
19336  int XLinkPosition = PDVIt->XLinkPos;
19337  if(PDVIt->XLinkPos == -1)
19338  {
19339  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19340  {
19341  for(int x = 0; x < 4; x++)
19342  {
19343  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19344  {
19345  XLinkPosition = x;
19346  break;
19347  }
19348  }
19349  }
19350  else
19351  {
19352  Utilities->CallLogPop(2549);
19353  return(false); //no point going any further
19354  }
19355  }
19356  if(XLinkPosition > -1) //should be by now but be safe
19357  {
19358  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19359  {
19360  FirstSignalFound = true; //the first signal doesn't change aspect
19361  continue;
19362  }
19363  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19364  {
19365 /*
19366  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19367  {
19368  continue; //ground signals don't fail
19369  }
19370 */
19371  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19372  {
19374  IFE.TVPos = PDVIt->TrackVectorPosition;
19375  TE.Failed = true;
19376  TE.Attribute = 0; //stop aspect
19377  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19378  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19379  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19380  " failed when changing aspect.\nTrains can only pass under signaller control.");
19381  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19382  //set repair time, random value in minutes between 10 and 179
19383  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19384  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19385  IFE.RepairTime = RepairTime;
19387  Track->FailedSignalsVector.push_back(IFE);
19389  int RouteNumber; //not used
19390  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19391  { // 0 for LinkPos ok as a signal so only one track
19392  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19393  }
19394  Utilities->CallLogPop(2535);
19395  return(true); //return so only allow one failure per route
19396  }
19397  }
19398  }
19399  }
19400  Utilities->CallLogPop(2531);
19401  return(false);
19402 }
19403 
19404 // ---------------------------------------------------------------------------
19405 // ---------------------------------------------------------------------------
19406 
19407 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19408 {
19409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19410  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19411  {
19412  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19413  }
19414  Utilities->CallLogPop(120);
19415  return(AllRoutesVector.at(At));
19416 }
19417 
19418 // ---------------------------------------------------------------------------
19419 
19421 {
19422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19423  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19424  {
19425  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19426  }
19427  Utilities->CallLogPop(121);
19428  return(AllRoutesVector.at(At));
19429 }
19430 
19431 // ---------------------------------------------------------------------------
19432 
19433 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19434 /*
19435  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19436 */
19437 {
19438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19439  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19440  {
19441  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19442  }
19443  Utilities->CallLogPop(351);
19444 }
19445 
19446 // ---------------------------------------------------------------------------
19447 
19448 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19449 {
19450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
19451  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19452  {
19453  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
19454  }
19455  Utilities->CallLogPop(1706);
19456 }
19457 
19458 // ---------------------------------------------------------------------------
19459 
19460 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
19461 /*
19462  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
19463  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
19464  Messages are given in TruncateRoute. If successful the route is truncated at and including
19465  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
19466  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
19467  length (train length).
19468 */
19469 {
19470  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
19471  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
19472  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19473  {
19474  TTruncateReturnType ReturnFlag;
19475 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
19476  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
19477  if(ReturnFlag == NotInRoute)
19478  {
19479  continue;
19480  }
19481  else if(ReturnFlag == InRouteTrue)
19482  {
19483  Utilities->CallLogPop(352);
19484  return(true);
19485  }
19486  else if(ReturnFlag == InRouteFalse)
19487  {
19488  Utilities->CallLogPop(353);
19489  return(false);
19490  }
19491  }
19492  Utilities->CallLogPop(354);
19493  return(false);
19494 }
19495 
19496 // ---------------------------------------------------------------------------
19497 
19498 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
19499 /*
19500  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
19501  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
19502 */
19503 {
19504  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
19505  AnsiString(LinkPos));
19506  if(TrackVectorPosition == -1) // allows for continuation entries & exits
19507  {
19508  Utilities->CallLogPop(355);
19509  return(false);
19510  }
19511  THVPair Route2MultiMapKeyPair;
19512 
19513  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
19514  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
19515  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19516  TRoute2MultiMapIterator Route2MultiMapIterator;
19517 
19518  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
19519  {
19520  Utilities->CallLogPop(356);
19521  return(false);
19522  }
19523  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
19524  {
19525  Utilities->CallLogPop(1422);
19526  return(true);
19527  }
19528  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
19529  {
19530  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19531 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19532 // realised after writing this that can't be points as would have been covered above, but leave anyway
19533  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
19534  Route2MultiMapIterator->second.second);
19535  EntryLinkPos = PrefDirElement1.ELinkPos;
19536  ExitLinkPos = PrefDirElement1.XLinkPos;
19537  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19538  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19539  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
19540  {
19541  Utilities->CallLogPop(357);
19542  return(true);
19543  }
19544  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
19545  {
19546  Utilities->CallLogPop(358);
19547  return(true);
19548  }
19549  }
19550  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
19551  {
19552  Utilities->CallLogPop(1423);
19553  return(true);
19554  }
19555  Utilities->CallLogPop(363);
19556  return(false); // none found
19557 }
19558 
19559 // ---------------------------------------------------------------------------
19560 
19561 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
19562  Graphics::TBitmap* &EntryDirectionGraphicPtr)
19563 /*
19564  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
19565  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
19566  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
19567  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
19568  for replotting of AutoSigsRoutes.
19569 */
19570 {
19571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19572  AnsiString(LinkPos));
19573  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19574  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19575  if(TrackVectorPosition == -1)
19576  {
19577  Utilities->CallLogPop(364);
19578  return(NoRoute); // allows for continuation entries & exits
19579  }
19580  THVPair Route2MultiMapKeyPair;
19581 
19582  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
19583  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
19584  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19585  TRoute2MultiMapIterator Route2MultiMapIterator;
19586 
19587  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19588  {
19589  Utilities->CallLogPop(365);
19590  return(NoRoute); // none found
19591  }
19592  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19593  {
19594  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19595 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19596  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
19597  Route2MultiMapIterator->second.second);
19598  EntryLinkPos = PrefDirElement1.ELinkPos;
19599  ExitLinkPos = PrefDirElement1.XLinkPos;
19600  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19601  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19602  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
19603  {
19604  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19605  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
19606  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19607  {
19608  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19609  }
19610  if(PrefDirElement1.AutoSignals)
19611  {
19612  Utilities->CallLogPop(366);
19613  return(AutoSigsRoute);
19614  }
19615  else
19616  {
19617  Utilities->CallLogPop(367);
19618  return(NotAutoSigsRoute);
19619  }
19620  }
19621  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
19622  {
19623  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19624  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
19625  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19626  {
19627  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19628  }
19629  if(PrefDirElement1.AutoSignals)
19630  {
19631  Utilities->CallLogPop(368);
19632  return(AutoSigsRoute);
19633  }
19634  else
19635  {
19636  Utilities->CallLogPop(369);
19637  return(NotAutoSigsRoute);
19638  }
19639  }
19640  }
19641  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19642  {
19643  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19644  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19645 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19646  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
19647  EntryLinkPos = PrefDirElement2.ELinkPos;
19648  ExitLinkPos = PrefDirElement2.XLinkPos;
19649  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19650  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19651  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
19652  {
19653  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19654  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
19655  {
19656  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19657  }
19658  if(PrefDirElement2.AutoSignals)
19659  {
19660  Utilities->CallLogPop(370);
19661  return(AutoSigsRoute);
19662  }
19663  else
19664  {
19665  Utilities->CallLogPop(371);
19666  return(NotAutoSigsRoute);
19667  }
19668  }
19669  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
19670  {
19671  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19672  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
19673  {
19674  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19675  }
19676  if(PrefDirElement2.AutoSignals)
19677  {
19678  Utilities->CallLogPop(372);
19679  return(AutoSigsRoute);
19680  }
19681  else
19682  {
19683  Utilities->CallLogPop(373);
19684  return(NotAutoSigsRoute);
19685  }
19686  }
19687  ItPair.second--; // the second iterator points one past the last matching value
19688  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
19689  EntryLinkPos = PrefDirElement3.ELinkPos;
19690  ExitLinkPos = PrefDirElement3.XLinkPos;
19691  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19692  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19693  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
19694  {
19695  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19696  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
19697  {
19698  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19699  }
19700  if(PrefDirElement3.AutoSignals)
19701  {
19702  Utilities->CallLogPop(374);
19703  return(AutoSigsRoute);
19704  }
19705  else
19706  {
19707  Utilities->CallLogPop(375);
19708  return(NotAutoSigsRoute);
19709  }
19710  }
19711  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
19712  {
19713  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19714  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
19715  {
19716  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19717  }
19718  if(PrefDirElement3.AutoSignals)
19719  {
19720  Utilities->CallLogPop(376);
19721  return(AutoSigsRoute);
19722  }
19723  else
19724  {
19725  Utilities->CallLogPop(377);
19726  return(NotAutoSigsRoute);
19727  }
19728  }
19729  }
19730  Utilities->CallLogPop(378);
19731  return(NoRoute); // none found
19732 }
19733 
19734 // ---------------------------------------------------------------------------
19735 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
19736 /*
19737  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
19738  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
19739 */
19740 {
19741  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
19742  AnsiString(LinkPos));
19743  if(TrackVectorPosition == -1)
19744  {
19745  RouteNumber = -1;
19746  Utilities->CallLogPop(379);
19747  return(NoRoute); // allows for continuation & buffer entries & exits
19748  }
19749  THVPair Route2MultiMapKeyPair;
19750 
19751  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
19752  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
19753  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19754  TRoute2MultiMapIterator Route2MultiMapIterator;
19755 
19756  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19757  {
19758  RouteNumber = -1;
19759  Utilities->CallLogPop(380);
19760  return(NoRoute); // none found
19761  }
19762  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19763  {
19764  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19765 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19766  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
19767  Route2MultiMapIterator->second.second);
19768  EntryLinkPos = PrefDirElement1.ELinkPos;
19769  ExitLinkPos = PrefDirElement1.XLinkPos;
19770  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19771  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19772  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
19773  {
19774  RouteNumber = Route2MultiMapIterator->second.first;
19775  if(PrefDirElement1.AutoSignals)
19776  {
19777  Utilities->CallLogPop(381);
19778  return(AutoSigsRoute);
19779  }
19780  else
19781  {
19782  Utilities->CallLogPop(382);
19783  return(NotAutoSigsRoute);
19784  }
19785  }
19786  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
19787  {
19788  RouteNumber = Route2MultiMapIterator->second.first;
19789  if(PrefDirElement1.AutoSignals)
19790  {
19791  Utilities->CallLogPop(383);
19792  return(AutoSigsRoute);
19793  }
19794  else
19795  {
19796  Utilities->CallLogPop(384);
19797  return(NotAutoSigsRoute);
19798  }
19799  }
19800  }
19801  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19802  {
19803  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19804  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19805 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19806  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
19807  EntryLinkPos = PrefDirElement2.ELinkPos;
19808  ExitLinkPos = PrefDirElement2.XLinkPos;
19809  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19810  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19811  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
19812  {
19813  RouteNumber = ItPair.first->second.first;
19814  if(PrefDirElement2.AutoSignals)
19815  {
19816  Utilities->CallLogPop(385);
19817  return(AutoSigsRoute);
19818  }
19819  else
19820  {
19821  Utilities->CallLogPop(386);
19822  return(NotAutoSigsRoute);
19823  }
19824  }
19825  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
19826  {
19827  RouteNumber = ItPair.first->second.first;
19828  if(PrefDirElement2.AutoSignals)
19829  {
19830  Utilities->CallLogPop(387);
19831  return(AutoSigsRoute);
19832  }
19833  else
19834  {
19835  Utilities->CallLogPop(388);
19836  return(NotAutoSigsRoute);
19837  }
19838  }
19839  ItPair.second--; // the second iterator points one past the last matching value
19840  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
19841  EntryLinkPos = PrefDirElement3.ELinkPos;
19842  ExitLinkPos = PrefDirElement3.XLinkPos;
19843  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19844  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19845  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
19846  {
19847  RouteNumber = ItPair.second->second.first;
19848  if(PrefDirElement3.AutoSignals)
19849  {
19850  Utilities->CallLogPop(389);
19851  return(AutoSigsRoute);
19852  }
19853  else
19854  {
19855  Utilities->CallLogPop(390);
19856  return(NotAutoSigsRoute);
19857  }
19858  }
19859  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
19860  {
19861  RouteNumber = ItPair.second->second.first;
19862  if(PrefDirElement3.AutoSignals)
19863  {
19864  Utilities->CallLogPop(391);
19865  return(AutoSigsRoute);
19866  }
19867  else
19868  {
19869  Utilities->CallLogPop(392);
19870  return(NotAutoSigsRoute);
19871  }
19872  }
19873  }
19874  RouteNumber = -1;
19875  Utilities->CallLogPop(393);
19876  return(NoRoute); // none found
19877 }
19878 
19879 // ---------------------------------------------------------------------------
19880 
19881 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
19882 /*
19883  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
19884  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
19885  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
19886  and Route2MultiMap.
19887 */
19888 {
19889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
19890  TOneRoute EmptyRoute;
19891 
19892  EmptyRoute.RouteID = NextRouteID;
19893  NextRouteID++;
19894 
19895  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19896  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19897  {
19898  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
19899  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
19900  }
19901  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
19902  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
19903 
19904  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
19905  Utilities->CallLogPop(394);
19906 }
19907 
19908 // ---------------------------------------------------------------------------
19909 
19911 /*
19912  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
19913  that is already in Route is used.
19914 */
19915 {
19916  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
19917  TOneRoute EmptyRoute;
19918 
19919  EmptyRoute.RouteID = Route->RouteID;
19920 
19921  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19922  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19923  {
19924  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
19925  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
19926  }
19927  Utilities->CallLogPop(1579);
19928 }
19929 
19930 // ---------------------------------------------------------------------------
19931 
19932 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
19933 /*
19934  When attaching a new route section to an existing route, it is sometimes necessary to erase the
19935  original route and create a new composite route. This function Erases all elements in the route
19936  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
19937  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
19938  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
19939  that are greater than the route number that is removed. The LockedRouteVector as also searched
19940  and if any relate to the route that has been cleared they are erased too, but the fact that one
19941  has been found is recorded so that it can be re-established later.
19942 */
19943 {
19944  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
19945  THVPair Route2MultiMapKeyPair;
19946  TRoute2MultiMapEntry Route2MultiMapEntry;
19947  TRoute2MultiMapIterator Route2MultiMapIterator;
19948 
19949 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
19950 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
19951 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
19952 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
19953 // If so the locked route is removed from the locked vector and is lost.
19954  LockedRouteRearTrackVectorPosition = 0;
19955  LockedRouteLastTrackVectorPosition = 0;
19956  LockedRouteLastXLinkPos = 0;
19957  LockedRouteLockStartTime = TDateTime(0);
19958  if(!LockedRouteVector.empty())
19959  {
19960  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19961  {
19962  if(LRVIT->RouteNumber == RouteNumber)
19963  {
19964  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
19965  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
19966  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
19967  LockedRouteLockStartTime = LRVIT->LockStartTime;
19968  LockedRouteFoundDuringRouteBuilding = true;
19969  LockedRouteVector.erase(LRVIT);
19970  }
19971  }
19972  }
19973  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
19974  {
19975  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
19976  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
19977  }
19978  Utilities->CallLogPop(395);
19979 }
19980 
19981 // ---------------------------------------------------------------------------
19982 
19984  TRoute2MultiMapIterator &Route2MultiMapIterator)
19985 /*
19986  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
19987  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
19988  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
19989  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
19990  are given for failure.
19991 */
19992 {
19993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19994  AnsiString(VLoc) + "," + AnsiString(ELink));
19995  TRouteElementPair ReturnPair;
19996 
19997  ReturnPair.first = -1;
19998  ReturnPair.second = 0;
19999  THVPair Route2MultiMapKeyPair;
20000 
20001  Route2MultiMapKeyPair.first = HLoc;
20002  Route2MultiMapKeyPair.second = VLoc;
20003  TRoute2MultiMapEntry Route2MultiMapEntry;
20004 
20005  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20006  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20007 
20008  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20009  Route2MultiMapIterator = ItPair.first;
20010 
20011  if(ItPair.first == ItPair.second)
20012  {
20013  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20014  }
20015  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20016  {
20017  ReturnPair.first = ItPair.first->second.first;
20018  ReturnPair.second = ItPair.first->second.second;
20019  Route2MultiMapIterator = ItPair.first;
20020  Utilities->CallLogPop(396);
20021  return(ReturnPair);
20022  }
20023  ItPair.first++;
20024  if(ItPair.first == ItPair.second)
20025  {
20026  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20027  }
20028  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20029  {
20030  ReturnPair.first = ItPair.first->second.first;
20031  ReturnPair.second = ItPair.first->second.second;
20032  Route2MultiMapIterator = ItPair.first;
20033  Utilities->CallLogPop(397);
20034  return(ReturnPair);
20035  }
20036  Utilities->CallLogPop(398);
20037  return(ReturnPair);
20038 }
20039 
20040 // ---------------------------------------------------------------------------
20041 
20042 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20043 /*
20044  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20045  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20046  RouteNumber (route position in AllRoutes vector is returned as a reference.
20047  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20048  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20049 */
20050 {
20051  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20052  AnsiString(VLoc) + "," + AnsiString(ELink));
20053  THVPair Route2MultiMapKeyPair;
20054 
20055  Route2MultiMapKeyPair.first = HLoc;
20056  Route2MultiMapKeyPair.second = VLoc;
20057  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20058 
20059  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20060 
20061  if(ItPair.first == ItPair.second)
20062  {
20063  RouteNumber = -1;
20064  Utilities->CallLogPop(2032);
20065  return(false);
20066  }
20067  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20068  {
20069  RouteNumber = ItPair.first->second.first;
20070  Utilities->CallLogPop(2033);
20071  return(true);
20072  }
20073  ItPair.first++;
20074 
20075  if(ItPair.first == ItPair.second)
20076  {
20077  RouteNumber = -1;
20078  Utilities->CallLogPop(2034);
20079  return(false);
20080  }
20081  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20082  {
20083  RouteNumber = ItPair.first->second.first;
20084  Utilities->CallLogPop(2035);
20085  return(true);
20086  }
20087  RouteNumber = -1;
20088  Utilities->CallLogPop(2036);
20089  return(false);
20090 }
20091 
20092 // ---------------------------------------------------------------------------
20093 
20094 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20095 /*
20096  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20097  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20098  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20099  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20100  Called by TAllRoutes::AddRouteElement.
20101 */
20102 {
20103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20104  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20105  THVPair Route2MultiMapKeyPair;
20106 
20107  Route2MultiMapKeyPair.first = HLoc;
20108  Route2MultiMapKeyPair.second = VLoc;
20109  TRoute2MultiMapEntry Route2MultiMapEntry;
20110 
20111  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20112  TRouteElementPair RouteElementPair;
20113 
20114  RouteElementPair.first = RouteNumber;
20115  RouteElementPair.second = RouteElementNumber;
20116  Route2MultiMapEntry.second = RouteElementPair;
20117 
20118  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20119  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20120  {
20121  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20122  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20123  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20124  {
20125  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20126  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20127  {
20128  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20129  }
20130  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20131  }
20132  else
20133  // same ELink so have an error
20134  {
20135  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20136  }
20137  }
20138  else
20139  {
20140  Route2MultiMap.insert(Route2MultiMapEntry);
20141  }
20142 // element at H&V not found in map so insert it
20143  Utilities->CallLogPop(399);
20144 }
20145 
20146 // ---------------------------------------------------------------------------
20147 
20149 /*
20150  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20151  and the second in the reference SecondPair. If there's only one then it's the function return
20152 */
20153 {
20154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20155  AnsiString(VLoc));
20157 
20158  TempPair.first = -1;
20159  TempPair.second = 0;
20160  SecondPair = TempPair;
20161  TRoute2MultiMapIterator Route2MultiMapIterator;
20162  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20163  THVPair Route2MultiMapKeyPair;
20164 
20165  Route2MultiMapKeyPair.first = HLoc;
20166  Route2MultiMapKeyPair.second = VLoc;
20167  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20168  {
20169  Utilities->CallLogPop(400);
20170  return(TempPair);
20171  }
20172  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20173  {
20174  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20175  Utilities->CallLogPop(401);
20176  return(Route2MultiMapIterator->second);
20177  }
20178  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20179  {
20180  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20181  TempPair = ItRange.first->second;
20182  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20183  Utilities->CallLogPop(402);
20184  return(TempPair);
20185  }
20186  Utilities->CallLogPop(403);
20187  return(TempPair);
20188 }
20189 
20190 // ---------------------------------------------------------------------------
20191 
20192 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20193 /*
20194  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20195  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20196 */
20197 {
20198  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20199  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20200  {
20201  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20202  {
20203  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20204  TAllRoutes::TRouteElementPair SecondPair;
20205  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20206  if(RouteElementPair.first == -1)
20207  // failed to find element in multimap
20208  {
20209  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20210  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20211  }
20212  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20213  // neither pair has expected route number
20214  {
20215  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20216  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20217  (AnsiString)Caller);
20218  }
20219  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20220  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20221  {
20222  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20223  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20224  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20225  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20226  }
20227  }
20228  }
20229  unsigned int SizeVal = 0;
20230 
20231 // check map and sum of route sizes match
20232  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20233  {
20234  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20235  }
20236  if(SizeVal != Route2MultiMap.size())
20237  {
20238  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20239  (AnsiString)Caller);
20240  }
20241  Utilities->CallLogPop(404);
20242  return;
20243 }
20244 
20245 // ---------------------------------------------------------------------------
20246 
20247 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20248 /*
20249  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20250  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20251  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20252 */
20253 {
20254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20255  if(!Route2MultiMap.empty())
20256  {
20257  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20258  {
20259  if(Route2MultiMapIterator->second.first > RouteNumber)
20260  {
20261  Route2MultiMapIterator->second.first--;
20262  }
20263  }
20264  }
20265  Utilities->CallLogPop(405);
20266 }
20267 
20268 // ---------------------------------------------------------------------------
20269 
20270 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20271 /*
20272  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20273  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20274  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20275 */
20276 {
20277  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20278  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20279  if(!Route2MultiMap.empty())
20280  {
20281  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20282  {
20283  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20284  {
20285  Route2MultiMapIterator->second.second--;
20286  }
20287  }
20288  }
20289  Utilities->CallLogPop(406);
20290 }
20291 
20292 // ---------------------------------------------------------------------------
20293 
20294 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20295 /*
20296  Erases the route element from Route2MultiMap and from the PrefDirVector.
20297  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20298  decremented if they are greater than the element number removed, and if the entire route is removed
20299  then the route numbers are also decremented in the map for route numbers that are greater than the route
20300  number that is removed.
20301 */
20302 {
20303  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20304  AnsiString(ELink));
20305  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20306  TRoute2MultiMapIterator Route2MultiMapIterator;
20307 
20308  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20309  if(RequiredRoutePair.first == -1)
20310  {
20311  throw Exception("Failed to find route element in RemoveRouteElement");
20312  }
20313  Route2MultiMap.erase(Route2MultiMapIterator);
20314  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20315 
20316 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20317  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20318 
20319  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20320  {
20321  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20322  }
20323 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20324 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20325 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20326 // to check if a route element is present, and the element has already been removed from the map - see above.
20327 
20328 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20329 /*
20330  int LockedVectorNumber = -1;
20331  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20332  {
20333  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20334  }
20335 */
20336 
20337 // erase element from route
20338  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20339 // CheckMapAndRoutes();//test - drop - tested below
20340 
20341 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20342 // be so as continuation exit is at the end of the route, and truncation is from the end
20344  {
20346  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20347  AutoSigVectorIT--)
20348  {
20349  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20350  {
20351  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20352  }
20353  }
20354  }
20355 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20356 // and adjust all the corresponding route numbers
20357  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20358  {
20359  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20360  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20361  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20362 
20363 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20364  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20365  it is erased then - see TInterface::ApproachLocking
20366 
20367  if(LockedVectorNumber > -1)
20368  {
20369  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20370  }
20371 */
20372  // decrement route numbers in the locked route vector whether or not this route is a locked route
20373  if(!LockedRouteVector.empty())
20374  {
20375  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20376  {
20377  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20378  {
20379  LRVIT->RouteNumber--;
20380  }
20381  }
20382  }
20384  {
20386  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20387  AutoSigVectorIT--)
20388  {
20389  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20390  {
20391  AutoSigVectorIT->RouteNumber--;
20392  }
20393  }
20394  }
20395  }
20396  CheckMapAndRoutes(7); // test
20397  Utilities->CallLogPop(407);
20398 }
20399 
20400 // ---------------------------------------------------------------------------
20401 
20402 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20403 /*
20404  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20405  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20406  since that catches all route elements wherever created
20407 */
20408 {
20409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20410  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20411  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20412  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20413  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20414 } //number is one less than this
20415 
20416 // ---------------------------------------------------------------------------
20417 
20418 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20419 /*
20420  Enter with signal at TrackVectorElement already set to red by the passing train.
20421  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20422  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20423  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20424  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20425  set signals in rear as it passed them.
20426 */
20427 {
20428  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20429  "," + AnsiString(XLinkPos));
20430  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20431  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20432 
20433  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20434  if(RouteElementPair.first == -1)
20435  {
20436  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20437  }
20438  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20439 
20440  RequiredPair = RouteElementPair;
20441  if(RouteElement.XLinkPos != XLinkPos)
20442  {
20443  if(SecondPair.first != -1)
20444  {
20445  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20446  RequiredPair = SecondPair;
20447  if(RouteElement.XLinkPos != XLinkPos)
20448  {
20449  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20450  }
20451  }
20452  else
20453  {
20454  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
20455  }
20456  }
20457 // new function
20458  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
20459  Utilities->CallLogPop(409);
20460 }
20461 
20462 // ---------------------------------------------------------------------------
20463 
20464 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
20465 /*
20466  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
20467  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
20468  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
20469  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
20470  changes from 0 to 1 to 2 for successive calls.
20471  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
20472  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
20473  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
20474  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
20475  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
20476 */
20477 {
20478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
20479  AnsiString(AccessNumber));
20480  TPrefDirElement RouteElement;
20481  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
20482 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
20483  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
20484 
20485  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
20486  {
20487  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
20488  }
20489  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
20490  {
20491  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
20492  }
20493  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
20494  x).XLinkPos] != End)
20495  {
20496  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
20497  }
20498 // new function
20499  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
20500  Utilities->CallLogPop(410);
20501 }
20502 
20503 // ---------------------------------------------------------------------------
20504 
20505 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
20506 /*
20507  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
20508  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
20509  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
20510  if autosigs the train will have set signals in rear as it passed them.
20511 
20512  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
20513  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
20514  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
20515  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
20516  then the function terminates.
20517 
20518  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
20519  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
20520  non-autosigs route, otherwise the signals won't be set behind the train.
20521 
20522  First the route is examined element by element from the RouteStartPosition towards the start of the
20523  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
20524  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
20525  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
20526  found behind the train.
20527 
20528  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
20529  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
20530  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
20531  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
20532  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
20533  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
20534  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
20535  or (c) truncating a route.
20536 
20537  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
20538  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
20539  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
20540  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
20541  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
20542  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
20543  the function returns true.
20544 
20545  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
20546  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
20547 */
20548 {
20549  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
20550  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
20551  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
20552  int RearwardLinkedRouteNumber;
20553 
20554 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
20555  bool SkipForwardLook = false; //allow forward look in first call
20556  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
20557  //Attribute to 1+ final signal value in the route for use in further linked routes
20558  {
20559  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
20560  { //linked rearwards route)
20561  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20562  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
20563  {
20564  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
20565  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
20566  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
20567  {
20568  break;
20569  }
20570  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
20571  }
20572  }
20573  }
20574  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
20575  {
20576  int TrainID, TrainPosition, BehindTrainPosition;
20577  bool FoundTrain = false, BehindTrain = false;
20578  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
20579  {
20580  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
20581  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
20582  TrainID = TrackElement.TrainIDOnElement;
20583  if(TrackElement.TrackType == Bridge)
20584  {
20585  if(PrefDirElement.XLinkPos < 2)
20586  {
20587  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20588  }
20589  else
20590  {
20591  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20592  }
20593  }
20594  if(TrainID == -1)
20595  {
20596  continue;
20597  }
20598  else
20599  {
20600  FoundTrain = true;
20601  TrainPosition = x;
20602  break;
20603  }
20604  }
20605  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
20606  { //If there is a linked rear route then no need to deal with signals behind train here -
20607  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
20608  //set signals in rear as it passed them.
20609  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
20610  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
20611  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
20612  // need the element behind the rearmost train.
20613  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
20614  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
20615  TrainID = TrackElement.TrainIDOnElement;
20616  if(TrackElement.TrackType == Bridge)
20617  {
20618  if(PrefDirElement.XLinkPos < 2)
20619  {
20620  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20621  }
20622  else
20623  {
20624  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20625  }
20626  }
20627  if(TrainID != -1)
20628  {
20629  continue; // still on train
20630  }
20631  else
20632  {
20633  BehindTrain = true;
20634  BehindTrainPosition = x;
20635  break;
20636  }
20637  }
20638  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
20639  // so on for as many trains as there are on this (RouteNumber) route
20640  {
20641  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
20642  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
20643  } //for rearward signal setting
20644  }
20645  }
20646  Utilities->CallLogPop(411);
20647 }
20648 
20649 // ---------------------------------------------------------------------------
20650 
20651 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
20652 {
20653 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
20654 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
20655 rearmost linked route) - this because train cancels route elements that it touches)
20656 */
20657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
20658  AnsiString(LookBackwardsFromHere));
20659  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
20660  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
20661  TPrefDirElement PrefDirElement, FirstElement;
20662  TTrackElement TrackElement;
20663  bool ExamineRoute = true;
20664 
20665  while(ExamineRoute)
20666  {
20667  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
20668  {
20669  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
20670  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
20671  TrainID = TrackElement.TrainIDOnElement;
20672  if(TrackElement.TrackType == Bridge)
20673  {
20674  if(PrefDirElement.XLinkPos < 2)
20675  {
20676  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20677  }
20678  else
20679  {
20680  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20681  }
20682  }
20683  if(TrainID > -1)
20684  {
20685  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
20686  {
20687  //any trains further back in route will be protected by the red signal behind the stopped train
20688  Utilities->CallLogPop(412);
20689  return(false);
20690  }
20691  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
20692  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
20693  //other way & can cancel the route
20694  {
20695  Utilities->CallLogPop(2203);
20696  return(false);
20697  }
20698  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
20699  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
20700  }
20701  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
20702  {
20703  if(TrackElement.Attribute == 0)
20704  {
20705  Utilities->CallLogPop(413);
20706  return(false); // OK, red signal in front of a train
20707  }
20708  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
20709  {
20710  SignalCount++;
20711  }
20712  if(SignalCount >= 3)
20713  {
20714  Utilities->CallLogPop(414);
20715  return(false);
20716  }
20717  }
20718  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
20719  // ElinkPos because working back along PrefDir to beginning
20720  {
20721  Utilities->CallLogPop(415);
20722  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
20723  }
20724  }
20725  //now look at linked rearwards routes
20726  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
20727  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
20728  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20729  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
20730  {
20731  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
20732  ExamineRoute = true;
20733  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
20734  }
20735  else
20736  {
20737  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
20738  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
20739  TrainID = PriorTrackElement.TrainIDOnElement;
20740  if(PriorTrackElement.TrackType == Bridge)
20741  {
20742  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
20743  {
20744  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20745  }
20746  else
20747  {
20748  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20749  }
20750  }
20751  if(TrainID > -1)
20752  {
20753  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
20754  {
20755  Utilities->CallLogPop(748);
20756  return(false);
20757  }
20758  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
20759  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
20760  //other way & can cancel the route
20761  {
20762  Utilities->CallLogPop(2204);
20763  return(false);
20764  }
20765  Utilities->CallLogPop(1962);
20766  return(true); //otherwise need to lock the route
20767  }
20768  ExamineRoute = false;
20769  }
20770  }
20771 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
20772 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
20773  Utilities->CallLogPop(416);
20774  return(false);
20775 }
20776 
20777 // ---------------------------------------------------------------------------
20778 
20779 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
20780  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
20781 {
20782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
20783  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
20784  TPrefDirElement InternalPrefDirElement; // blank element
20785 
20786  PrefDirElement = InternalPrefDirElement;
20787  if(LockedRouteVector.empty())
20788  {
20789  Utilities->CallLogPop(417);
20790  return(false);
20791  }
20792 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
20793 // even if some elements have been removed from the front by a train
20794  bool InLockedRoute = false;
20795 
20796  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20797  {
20798  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
20799  {
20800  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
20801  // doesn't arise)
20802  InLockedRoute = true;
20803  break;
20804  }
20805  }
20806  if(!InLockedRoute)
20807  {
20808  Utilities->CallLogPop(418);
20809  return(false);
20810  }
20811  int RouteNumber, VectorCount = 0;
20812  TRouteType RouteType;
20813 
20814  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20815  {
20816  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
20817  if(RouteType == NoRoute)
20818  {
20819  continue;
20820  }
20821 /* can't use this test with front truncation
20822  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
20823  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
20824  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
20825  {
20826  throw Exception
20827  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
20828  }
20829 */
20830  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
20831  {
20832  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
20833  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
20834  {
20835  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20836  {
20837  PrefDirElement = InternalPrefDirElement;
20838  LockedVectorNumber = VectorCount;
20839  Utilities->CallLogPop(419);
20840  return(true);
20841  }
20842  }
20843  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
20844  {
20845  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20846  {
20847  PrefDirElement = InternalPrefDirElement;
20848  LockedVectorNumber = VectorCount;
20849  Utilities->CallLogPop(420);
20850  return(true);
20851  }
20852  else
20853  {
20854  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
20855  }
20856  }
20857  }
20858  VectorCount++;
20859  }
20860  Utilities->CallLogPop(421);
20861  return(false);
20862 }
20863 
20864 // ---------------------------------------------------------------------------
20865 
20867 {
20868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
20869  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20870  {
20871  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
20872  {
20873  Utilities->CallLogPop(963);
20874  return(x);
20875  }
20876  }
20877  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
20878 }
20879 
20880 // ---------------------------------------------------------------------------
20881 
20883 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
20884 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
20885 {
20886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20887  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20888  {
20889  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
20890  {
20891  Utilities->CallLogPop(2039);
20892  return(true);
20893  }
20894  }
20895  Utilities->CallLogPop(2040);
20896  return(false);
20897 }
20898 
20899 // ---------------------------------------------------------------------------
20900 
20902 {
20903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20904  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20905  {
20906  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
20907  {
20908  Utilities->CallLogPop(964);
20909  return(GetFixedRouteAt(159, x));
20910  }
20911  }
20912  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20913 }
20914 
20915 // ---------------------------------------------------------------------------
20916 
20918 {
20919  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
20920  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20921  {
20922  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
20923  {
20924  Utilities->CallLogPop(965);
20925  return(GetModifiableRouteAt(15, x));
20926  }
20927  }
20928  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20929 }
20930 
20931 // ---------------------------------------------------------------------------
20932 
20933 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
20934 {
20935  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
20936  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
20937  Utilities->SaveFileInt(OutFile, NextRouteID);
20938  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20939  {
20940  TOneRoute OneRoute = GetFixedRouteAt(165, x);
20941  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
20942  OneRoute.SavePrefDirVector(6, OutFile);
20943  }
20944  Utilities->CallLogPop(1442);
20945 }
20946 
20947 // ---------------------------------------------------------------------------
20948 
20949 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
20950 {
20951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
20952  int NumberOfRoutes;
20953 
20954  NumberOfRoutes = Utilities->LoadFileInt(InFile);
20955  NextRouteID = Utilities->LoadFileInt(InFile);
20956  for(int x = 0; x < NumberOfRoutes; x++)
20957  {
20958  TOneRoute OneRoute; // empty route
20959  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
20960  OneRoute.LoadPrefDir(2, InFile);
20962  {
20963  StoreOneRouteAfterSessionLoad(0, &OneRoute);
20964  }
20965  else
20966  {
20967  Utilities->CallLogPop(1443);
20968  return(false);
20969  }
20970  }
20971  Utilities->CallLogPop(1444);
20972  return(true);
20973 }
20974 
20975 // ---------------------------------------------------------------------------
20976 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
20977 {
20978  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
20979  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
20980 
20981  if((NumberOfRoutes < 0) || (NumberOfRoutes > 10000)) //increased from 5000 to 10000 at v2.20.3 because of Jason B's WCML railway (was 304 but could get higher)
20982  {
20983  Utilities->CallLogPop(1445);
20984  return(false);
20985  }
20986  int NextID = Utilities->LoadFileInt(InFile);
20987 
20988  if((NextID < 0) || (NextID > 1000000))
20989  {
20990  Utilities->CallLogPop(1446);
20991  return(false);
20992  }
20993  for(int x = 0; x < NumberOfRoutes; x++)
20994  {
20995  int RouteID = Utilities->LoadFileInt(InFile);
20996  if((RouteID < 0) || (RouteID > 1000000)) //increased from 20000 t0 1000000 at v2.20.3 because of Jason B's WCML railway where RouteID was 22009
20997  {
20998  Utilities->CallLogPop(1447);
20999  return(false);
21000  }
21001  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
21002  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21003  {
21004  Utilities->CallLogPop(1448);
21005  return(false);
21006  }
21007  }
21008  Utilities->CallLogPop(1449);
21009  return(true);
21010 }
21011 
21012 // ---------------------------------------------------------------------------
21013 
21014 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21015 {
21016  // return true for a loop
21017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21018  AnsiString(StartPosition));
21019  if(EndPosition == StartPosition)
21020  {
21021  Utilities->CallLogPop(1839);
21022  return(true); // shouldn't happen but treat as a loop if does
21023  }
21024 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21025  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21026  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21027 
21028  while(TrackIsInARoute(15, TVPos, LkPos))
21029  {
21030  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21031  int NewLkPos = -1;
21032  if(NewTVPos > -1)
21033  {
21034  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21035  if(NewLkPos == -1)
21036  {
21037  Utilities->CallLogPop(1840);
21038  return(true); // shouldn't arise but treat as loop if does
21039  }
21040  }
21041  else // reached a buffer or continuation
21042  {
21043  Utilities->CallLogPop(1841);
21044  return(false);
21045  }
21046 //Error found by Xeon notified by email 13/10/20.
21047 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21048 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21049 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21050 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21051 //New check added for v2.6.0
21052 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21053 //as possible in case there are other unforeseen effects.
21054  int RouteNumber; //dummy, not used
21055  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21056  {
21057  Utilities->CallLogPop(2241);
21058  return(false);
21059  }
21060  //now make the connected element the current element, read across the TV number and determine the exit link
21061  TVPos = NewTVPos;
21062  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21063  {
21064  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21065  {
21066  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21067  {
21068  LkPos = 1;
21069  }
21070  else
21071  {
21072  LkPos = 3;
21073  }
21074  }
21075  else
21076  {
21077  LkPos = 0;
21078  }
21079  }
21080  else
21081  {
21082  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21083  }
21084  if(TVPos == StartPosition)
21085  {
21086  Utilities->CallLogPop(1842);
21087  return(true); // it is a loop
21088  }
21089  }
21090  Utilities->CallLogPop(1843);
21091  return(false); // reached end of route so not a loop
21092 }
21093 
21094 // ---------------------------------------------------------------------------
21095 
21096 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21097 /*
21098  Track geometry allows diagonals to cross without occupying the same track element, so when
21099  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21100  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21101  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21102  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21103  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21104  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21105  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21106  Each of these is examined in turn for each route element in the relevant position.
21107 
21108  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21109  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21110  that returns false in all cases (including elements & links not present) except train present.
21111 */
21112 {
21113  int TrainID; // not used in this function
21114 
21115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21116  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21117  TPrefDirElement TempPrefDirElement;
21118  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21119 
21120  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
21121  if(FirstPair.first > -1)
21122  {
21123  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21124  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21125  {
21126  Utilities->CallLogPop(310);
21127  return(true);
21128  }
21129  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21130  {
21131  Utilities->CallLogPop(311);
21132  return(true);
21133  }
21134  }
21135  if(SecondPair.first > -1)
21136  {
21137  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21138  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21139  {
21140  Utilities->CallLogPop(312);
21141  return(true);
21142  }
21143  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21144  {
21145  Utilities->CallLogPop(313);
21146  return(true);
21147  }
21148  }
21149  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
21150  9, TrainID)))
21151  {
21152  Utilities->CallLogPop(1997);
21153  return(true);
21154  }
21155  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
21156  if(FirstPair.first > -1)
21157  {
21158  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21159  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21160  {
21161  Utilities->CallLogPop(314);
21162  return(true);
21163  }
21164  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21165  {
21166  Utilities->CallLogPop(315);
21167  return(true);
21168  }
21169  }
21170  if(SecondPair.first > -1)
21171  {
21172  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21173  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21174  {
21175  Utilities->CallLogPop(316);
21176  return(true);
21177  }
21178  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21179  {
21180  Utilities->CallLogPop(317);
21181  return(true);
21182  }
21183  }
21184  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
21185  9, TrainID)))
21186  {
21187  Utilities->CallLogPop(1998);
21188  return(true);
21189  }
21190  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
21191  if(FirstPair.first > -1)
21192  {
21193  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21194  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21195  {
21196  Utilities->CallLogPop(318);
21197  return(true);
21198  }
21199  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21200  {
21201  Utilities->CallLogPop(319);
21202  return(true);
21203  }
21204  }
21205  if(SecondPair.first > -1)
21206  {
21207  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21208  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21209  {
21210  Utilities->CallLogPop(320);
21211  return(true);
21212  }
21213  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21214  {
21215  Utilities->CallLogPop(321);
21216  return(true);
21217  }
21218  }
21219  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
21220  7, TrainID)))
21221  {
21222  Utilities->CallLogPop(1999);
21223  return(true);
21224  }
21225  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
21226  if(FirstPair.first > -1)
21227  {
21228  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21229  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21230  {
21231  Utilities->CallLogPop(322);
21232  return(true);
21233  }
21234  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21235  {
21236  Utilities->CallLogPop(323);
21237  return(true);
21238  }
21239  }
21240  if(SecondPair.first > -1)
21241  {
21242  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21243  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21244  {
21245  Utilities->CallLogPop(324);
21246  return(true);
21247  }
21248  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21249  {
21250  Utilities->CallLogPop(325);
21251  return(true);
21252  }
21253  }
21254  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
21255  3, TrainID)))
21256  {
21257  Utilities->CallLogPop(2000);
21258  return(true);
21259  }
21260  Utilities->CallLogPop(326);
21261  return(false);
21262 }
21263 
21264 // ---------------------------------------------------------------------------
21265 
21266 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21267 /*
21268  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21269  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21270  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21271  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21272  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21273  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21274  Each of these is examined in turn for each route element in the relevant position.
21275 */
21276 {
21277  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21278  "," + AnsiString(DiagonalLinkNumber));
21279  TPrefDirElement TempPrefDirElement;
21280  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21281 
21282  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
21283  if(FirstPair.first > -1)
21284  {
21285  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21286  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21287  {
21288  Utilities->CallLogPop(2010);
21289  return(true);
21290  }
21291  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21292  {
21293  Utilities->CallLogPop(2011);
21294  return(true);
21295  }
21296  }
21297  if(SecondPair.first > -1)
21298  {
21299  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21300  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21301  {
21302  Utilities->CallLogPop(2012);
21303  return(true);
21304  }
21305  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21306  {
21307  Utilities->CallLogPop(2013);
21308  return(true);
21309  }
21310  }
21311  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
21312  if(FirstPair.first > -1)
21313  {
21314  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21315  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21316  {
21317  Utilities->CallLogPop(2014);
21318  return(true);
21319  }
21320  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21321  {
21322  Utilities->CallLogPop(2015);
21323  return(true);
21324  }
21325  }
21326  if(SecondPair.first > -1)
21327  {
21328  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21329  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21330  {
21331  Utilities->CallLogPop(2016);
21332  return(true);
21333  }
21334  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21335  {
21336  Utilities->CallLogPop(2017);
21337  return(true);
21338  }
21339  }
21340  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
21341  if(FirstPair.first > -1)
21342  {
21343  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21344  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21345  {
21346  Utilities->CallLogPop(2018);
21347  return(true);
21348  }
21349  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21350  {
21351  Utilities->CallLogPop(2019);
21352  return(true);
21353  }
21354  }
21355  if(SecondPair.first > -1)
21356  {
21357  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21358  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21359  {
21360  Utilities->CallLogPop(2020);
21361  return(true);
21362  }
21363  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21364  {
21365  Utilities->CallLogPop(2021);
21366  return(true);
21367  }
21368  }
21369  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
21370  if(FirstPair.first > -1)
21371  {
21372  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21373  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21374  {
21375  Utilities->CallLogPop(2022);
21376  return(true);
21377  }
21378  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21379  {
21380  Utilities->CallLogPop(2023);
21381  return(true);
21382  }
21383  }
21384  if(SecondPair.first > -1)
21385  {
21386  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21387  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21388  {
21389  Utilities->CallLogPop(2024);
21390  return(true);
21391  }
21392  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21393  {
21394  Utilities->CallLogPop(2025);
21395  return(true);
21396  }
21397  }
21398  Utilities->CallLogPop(2026);
21399  return(false);
21400 }
21401 
21402 // ---------------------------------------------------------------------------
21403 
21404 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9194
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19498
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1326
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12238
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12211
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:439
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4796
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:573
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5671
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13756
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1742
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:814
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20094
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10288
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:20505
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1380
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:806
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14280
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:824
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:437
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13796
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3843
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:804
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:287
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7483
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:19460
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:97
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1722
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:730
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5823
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7384
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5850
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1536
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:593
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1683
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1977
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10741
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:623
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21266
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:439
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1713
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:70
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:614
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:558
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6003
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8411
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1546
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:652
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:19932
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:585
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13535
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7869
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:153
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10479
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9664
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14929
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:16888
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1141
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20294
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:762
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1663
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13339
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4546
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3723
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1560
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8226
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:445
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4706
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1340
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6667
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11516
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3599
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10990
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1339
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:20779
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2918
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7855
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:228
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:20976
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:581
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9833
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1721
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1558
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1650
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:210
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:742
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:443
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3323
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16691
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8703
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13601
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:808
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:77
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2934
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:732
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1042
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20042
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1407
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13852
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3922
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1783
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5963
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:306
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:745
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:382
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10504
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14800
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12252
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:577
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7884
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:89
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20402
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7630
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:614
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:575
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10846
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1562
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1524
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:715
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:587
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:810
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1416
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6251
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1564
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:625
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9057
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:570
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10955
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1055
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:305
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:748
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:816
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3896
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:875
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:232
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9798
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1036
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19448
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:509
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18249
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1677
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1687
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7898
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7076
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:650
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:230
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9096
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19433
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:828
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14569
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14306
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:928
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4631
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1927
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:437
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:788
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11719
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20247
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4892
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1946
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:798
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:764
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:565
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1746
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:660
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11964
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:20882
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1053
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2902
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1570
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15804
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7511
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8893
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7590
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5874
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:697
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:321
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1550
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:688
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:18953
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1342
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:875
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13940
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13075
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1688
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:86
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1740
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:794
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13568
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:715
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19079
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3700
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14259
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12007
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1829
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:940
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:584
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6057
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13388
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:828
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:629
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2957
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12264
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12583
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:434
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:119
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5922
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1863
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14507
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6134
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:894
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5714
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18496
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6648
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:95
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1371
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9592
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:714
TTrack::Up
@ Up
Definition: TrackUnit.h:614
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:830
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:588
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10969
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1518
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:379
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8860
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1681
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:760
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:206
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19166
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1670
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6534
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:832
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8806
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7539
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10261
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:575
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:593
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:796
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19735
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1597
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13438
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11903
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4715
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:573
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10941
TGraphicElement::Width
int Width
Definition: TrackUnit.h:441
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:20651
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:20866
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:19561
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:802
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:810
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15338
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:662
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4204
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2418
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:695
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9732
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2160
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13206
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:794
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:967
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5898
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:20949
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1562
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1552
TAllRoutes::RouteBackTruncateFlag
bool RouteBackTruncateFlag
used to flag the fact that a route is being truncated from the back in order to change the behaviour ...
Definition: TrackUnit.h:1727
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7237
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1066
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1068
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8070
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19258
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:663
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7612
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5519
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:828
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14329
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:621
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11815
Parapet
@ Parapet
Definition: TrackUnit.h:67
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19407
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:115
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:275
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9401
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19231
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:828
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20270
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:800
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:248
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1071
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:740
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:16464
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:208
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12035
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13133
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1320
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19194
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:551
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1379
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:875
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1410
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20418
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18149
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1720
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1657
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8380
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:591
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:206
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:19910
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:214
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3037
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9742
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6428
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:808
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2638
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:204
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1655
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:8034
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12921
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13699
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:589
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1524
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10878
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8769
IDInt
Definition: TrackUnit.h:500
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2644
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:20917
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4519
TDisplay
Definition: DisplayUnit.h:49
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10628
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5262
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:882
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:443
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21014
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1155
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9515
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:573
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7981
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1321
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:228
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14009
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:784
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:212
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15135
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1725
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7949
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:635
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:910
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1535
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1661
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1548
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1671
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4814
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9341
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:721
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16497
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1349
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:437
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14435
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1327
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14210
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:19983
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10192
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11886
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4226
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19143
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9574
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1899
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:39
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18039
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1062
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7828
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3800
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6154
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14107
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:593
TTrack::ThisLocationLongEnoughForSplit
bool ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement, int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
checks if the track that the train is on is long enough for a split, returns false if not,...
Definition: TrackUnit.cpp:11261
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9621
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12964
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:579
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:716
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:437
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1051
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:794
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3417
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:441
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1555
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:688
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:742
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1719
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:269
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21096
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13904
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1040
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1526
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1044
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:790
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:904
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4775
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:19881
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1752
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8907
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:699
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:124
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:812
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:710
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1381
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19285
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:717
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:20933
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:583
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1909
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4757
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3777
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9855
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17852
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12193
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12782
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8833
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12165
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1049
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20192
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20148
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7310
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11544
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:736
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1408
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18061
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5942
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:262
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:153
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:437
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:774
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10315
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:575
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:738
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:752
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19420
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4924
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2813
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7909
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3179
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18010
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:631
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14699
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:772
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:696
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1108
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12103
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1321
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:657
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:667
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12343
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:437
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1522
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:201
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8956
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:523
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1807
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9138
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:93
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:726
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14406
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:20901
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:613
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1378
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4435
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:818
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4648
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7772
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2004
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1057
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6574
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7567
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1410
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:214
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:669
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:782
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:717
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4673
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:792
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1665
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1064
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12135
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8331
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1334
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9772
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1038
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11780
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1814
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:105
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1524
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16918
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7755
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:822
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1526
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:618
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6591
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3677
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:100
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:114
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:586
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:758
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11706
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17334
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:683
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:627
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:690
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:826
RouteCall
@ RouteCall
Definition: TrackUnit.h:1327
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12277
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:91
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:673
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:20464
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:745
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11735
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10710
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:678
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:204
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
True if another train on LinkPos track of element at TrackPos, whether bridge or not,...
Definition: TrackUnit.cpp:11673
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6492
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15840
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:750
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12289
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1383
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1659
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1579
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:575
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10701
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1321
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17768
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:99
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12301
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4585
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12224
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11097